Merge branch 'master' of github.com:grpc/grpc into poll_fd_shutdown
diff --git a/.gitignore b/.gitignore
index 3cc35ff..3112445 100644
--- a/.gitignore
+++ b/.gitignore
@@ -96,10 +96,17 @@
 Pods/
 
 # Artifacts directory
-artifacts/
+/artifacts/
 
 # Git generated files for conflicting
 *.orig
 
 # IDE specific folder for JetBrains IDEs
 .idea/
+
+# Blaze files
+bazel-bin
+bazel-genfiles
+bazel-grpc
+bazel-out
+bazel-testlogs
diff --git a/.gitmodules b/.gitmodules
index 04d155c..c8ca8ab 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -20,3 +20,6 @@
 [submodule "third_party/benchmark"]
 	path = third_party/benchmark
 	url = https://github.com/google/benchmark
+[submodule "third_party/boringssl-with-bazel"]
+	path = third_party/boringssl-with-bazel
+	url = https://boringssl.googlesource.com/boringssl
diff --git a/BUILD b/BUILD
index ab0fc23..3122dc0 100644
--- a/BUILD
+++ b/BUILD
@@ -1,11 +1,6 @@
-# GRPC Bazel BUILD file.
-# This currently builds C, C++ and Objective-C code.
-# This file has been automatically generated from a template file.
-# Please look at the templates directory instead.
-# This file can be regenerated from the template by running
-# tools/buildgen/generate_projects.sh
-
-# Copyright 2015, Google Inc.
+# gRPC Bazel BUILD file.
+#
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -40,2884 +35,1200 @@
 
 package(default_visibility = ["//visibility:public"])
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_proto_plugin")
 
+g_stands_for = "good"
 
+core_version = "2.0.0-dev"
 
+version = "1.1.0-dev"
 
-cc_library(
-  name = "gpr",
-  srcs = [
-    "src/core/lib/profiling/timers.h",
-    "src/core/lib/support/backoff.h",
-    "src/core/lib/support/block_annotate.h",
-    "src/core/lib/support/env.h",
-    "src/core/lib/support/mpscq.h",
-    "src/core/lib/support/murmur_hash.h",
-    "src/core/lib/support/stack_lockfree.h",
-    "src/core/lib/support/string.h",
-    "src/core/lib/support/string_windows.h",
-    "src/core/lib/support/thd_internal.h",
-    "src/core/lib/support/time_precise.h",
-    "src/core/lib/support/tmpfile.h",
-    "src/core/lib/profiling/basic_timers.c",
-    "src/core/lib/profiling/stap_timers.c",
-    "src/core/lib/support/alloc.c",
-    "src/core/lib/support/avl.c",
-    "src/core/lib/support/backoff.c",
-    "src/core/lib/support/cmdline.c",
-    "src/core/lib/support/cpu_iphone.c",
-    "src/core/lib/support/cpu_linux.c",
-    "src/core/lib/support/cpu_posix.c",
-    "src/core/lib/support/cpu_windows.c",
-    "src/core/lib/support/env_linux.c",
-    "src/core/lib/support/env_posix.c",
-    "src/core/lib/support/env_windows.c",
-    "src/core/lib/support/histogram.c",
-    "src/core/lib/support/host_port.c",
-    "src/core/lib/support/log.c",
-    "src/core/lib/support/log_android.c",
-    "src/core/lib/support/log_linux.c",
-    "src/core/lib/support/log_posix.c",
-    "src/core/lib/support/log_windows.c",
-    "src/core/lib/support/mpscq.c",
-    "src/core/lib/support/murmur_hash.c",
-    "src/core/lib/support/stack_lockfree.c",
-    "src/core/lib/support/string.c",
-    "src/core/lib/support/string_posix.c",
-    "src/core/lib/support/string_util_windows.c",
-    "src/core/lib/support/string_windows.c",
-    "src/core/lib/support/subprocess_posix.c",
-    "src/core/lib/support/subprocess_windows.c",
-    "src/core/lib/support/sync.c",
-    "src/core/lib/support/sync_posix.c",
-    "src/core/lib/support/sync_windows.c",
-    "src/core/lib/support/thd.c",
-    "src/core/lib/support/thd_posix.c",
-    "src/core/lib/support/thd_windows.c",
-    "src/core/lib/support/time.c",
-    "src/core/lib/support/time_posix.c",
-    "src/core/lib/support/time_precise.c",
-    "src/core/lib/support/time_windows.c",
-    "src/core/lib/support/tls_pthread.c",
-    "src/core/lib/support/tmpfile_msys.c",
-    "src/core/lib/support/tmpfile_posix.c",
-    "src/core/lib/support/tmpfile_windows.c",
-    "src/core/lib/support/wrap_memcpy.c",
-  ],
+grpc_cc_library(
+    name = "gpr",
+    language = "c",
+    standalone = True,
+    deps = [
+        "gpr_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc",
+    srcs = [
+        "src/core/lib/surface/init.c",
+        "src/core/plugin_registry/grpc_plugin_registry.c",
+    ],
+    language = "c",
+    standalone = True,
+    deps = [
+        "census",
+        "grpc_base",
+        "grpc_lb_policy_grpclb",
+        "grpc_lb_policy_pick_first",
+        "grpc_lb_policy_round_robin",
+        "grpc_load_reporting",
+        "grpc_resolver_dns_native",
+        "grpc_resolver_sockaddr",
+        "grpc_secure",
+        "grpc_transport_chttp2_client_insecure",
+        "grpc_transport_chttp2_client_secure",
+        "grpc_transport_chttp2_server_insecure",
+        "grpc_transport_chttp2_server_secure",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_cronet",
+    srcs = [
+        "src/core/lib/surface/init.c",
+        "src/core/plugin_registry/grpc_cronet_plugin_registry.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_transport_chttp2_client_secure",
+        "grpc_transport_cronet_client_secure",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_unsecure",
+    srcs = [
+        "src/core/lib/surface/init.c",
+        "src/core/lib/surface/init_unsecure.c",
+        "src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
+    ],
+    language = "c",
+    standalone = True,
+    deps = [
+        "census",
+        "grpc_base",
+        "grpc_lb_policy_grpclb",
+        "grpc_lb_policy_pick_first",
+        "grpc_lb_policy_round_robin",
+        "grpc_load_reporting",
+        "grpc_resolver_dns_native",
+        "grpc_resolver_sockaddr",
+        "grpc_transport_chttp2_client_insecure",
+        "grpc_transport_chttp2_server_insecure",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc++",
+    srcs = [
+        "src/cpp/client/insecure_credentials.cc",
+        "src/cpp/client/secure_credentials.cc",
+        "src/cpp/common/auth_property_iterator.cc",
+        "src/cpp/common/secure_auth_context.cc",
+        "src/cpp/common/secure_channel_arguments.cc",
+        "src/cpp/common/secure_create_auth_context.cc",
+        "src/cpp/server/insecure_server_credentials.cc",
+        "src/cpp/server/secure_server_credentials.cc",
+    ],
+    hdrs = [
+        "include/grpc++/impl/codegen/core_codegen.h",
+        "src/cpp/client/secure_credentials.h",
+        "src/cpp/common/secure_auth_context.h",
+        "src/cpp/server/secure_server_credentials.h",
+    ],
+    language = "c++",
+    standalone = True,
+    deps = [
+        "gpr",
+        "grpc",
+        "grpc++_base",
+        "grpc++_codegen_base",
+        "grpc++_codegen_base_src",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc++_unsecure",
+    srcs = [
+        "src/cpp/client/insecure_credentials.cc",
+        "src/cpp/common/insecure_create_auth_context.cc",
+        "src/cpp/server/insecure_server_credentials.cc",
+    ],
+    language = "c++",
+    standalone = True,
+    deps = [
+        "gpr",
+        "grpc++_base",
+        "grpc++_codegen_base",
+        "grpc++_codegen_base_src",
+        "grpc_unsecure",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_plugin_support",
+    srcs = [
+        "src/compiler/cpp_generator.cc",
+        "src/compiler/csharp_generator.cc",
+        "src/compiler/node_generator.cc",
+        "src/compiler/objective_c_generator.cc",
+        "src/compiler/php_generator.cc",
+        "src/compiler/python_generator.cc",
+        "src/compiler/ruby_generator.cc",
+    ],
+    hdrs = [
+        "src/compiler/config.h",
+        "src/compiler/cpp_generator.h",
+        "src/compiler/cpp_generator_helpers.h",
+        "src/compiler/csharp_generator.h",
+        "src/compiler/csharp_generator_helpers.h",
+        "src/compiler/generator_helpers.h",
+        "src/compiler/node_generator.h",
+        "src/compiler/node_generator_helpers.h",
+        "src/compiler/objective_c_generator.h",
+        "src/compiler/objective_c_generator_helpers.h",
+        "src/compiler/php_generator.h",
+        "src/compiler/php_generator_helpers.h",
+        "src/compiler/python_generator.h",
+        "src/compiler/ruby_generator.h",
+        "src/compiler/ruby_generator_helpers-inl.h",
+        "src/compiler/ruby_generator_map-inl.h",
+        "src/compiler/ruby_generator_string-inl.h",
+    ],
+    external_deps = [
+        "protobuf_clib",
+    ],
+    language = "c++",
+    deps = [
+        "grpc++_config_proto",
+    ],
+)
+
+grpc_proto_plugin(
+    name = "grpc_cpp_plugin",
+    srcs = ["src/compiler/cpp_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_proto_plugin(
+    name = "grpc_csharp_plugin",
+    srcs = ["src/compiler/csharp_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_proto_plugin(
+    name = "grpc_node_plugin",
+    srcs = ["src/compiler/node_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_proto_plugin(
+    name = "grpc_objective_c_plugin",
+    srcs = ["src/compiler/objective_c_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_proto_plugin(
+    name = "grpc_php_plugin",
+    srcs = ["src/compiler/php_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_proto_plugin(
+    name = "grpc_python_plugin",
+    srcs = ["src/compiler/python_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_proto_plugin(
+    name = "grpc_ruby_plugin",
+    srcs = ["src/compiler/ruby_plugin.cc"],
+    deps = [":grpc_plugin_support"],
+)
+
+grpc_cc_library(
+    name = "grpc_csharp_ext",
+    srcs = [
+        "src/csharp/ext/grpc_csharp_ext.c",
+    ],
+    language = "csharp",
+    deps = [
+        "gpr",
+        "grpc",
+    ],
+)
+
+grpc_cc_library(
+    name = "census",
+    srcs = [
+        "src/core/ext/census/base_resources.c",
+        "src/core/ext/census/context.c",
+        "src/core/ext/census/gen/census.pb.c",
+        "src/core/ext/census/gen/trace_context.pb.c",
+        "src/core/ext/census/grpc_context.c",
+        "src/core/ext/census/grpc_filter.c",
+        "src/core/ext/census/grpc_plugin.c",
+        "src/core/ext/census/initialize.c",
+        "src/core/ext/census/mlog.c",
+        "src/core/ext/census/operation.c",
+        "src/core/ext/census/placeholders.c",
+        "src/core/ext/census/resource.c",
+        "src/core/ext/census/trace_context.c",
+        "src/core/ext/census/tracing.c",
+    ],
+    hdrs = [
+        "src/core/ext/census/aggregation.h",
+        "src/core/ext/census/base_resources.h",
+        "src/core/ext/census/census_interface.h",
+        "src/core/ext/census/census_rpc_stats.h",
+        "src/core/ext/census/gen/census.pb.h",
+        "src/core/ext/census/gen/trace_context.pb.h",
+        "src/core/ext/census/grpc_filter.h",
+        "src/core/ext/census/mlog.h",
+        "src/core/ext/census/resource.h",
+        "src/core/ext/census/rpc_metric_id.h",
+        "src/core/ext/census/trace_context.h",
+    ],
+    external_deps = [
+        "nanopb",
+    ],
+    language = "c",
+    public_hdrs = [
+        "include/grpc/census.h",
+    ],
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "gpr_base",
+    srcs = [
+        "src/core/lib/profiling/basic_timers.c",
+        "src/core/lib/profiling/stap_timers.c",
+        "src/core/lib/support/alloc.c",
+        "src/core/lib/support/avl.c",
+        "src/core/lib/support/backoff.c",
+        "src/core/lib/support/cmdline.c",
+        "src/core/lib/support/cpu_iphone.c",
+        "src/core/lib/support/cpu_linux.c",
+        "src/core/lib/support/cpu_posix.c",
+        "src/core/lib/support/cpu_windows.c",
+        "src/core/lib/support/env_linux.c",
+        "src/core/lib/support/env_posix.c",
+        "src/core/lib/support/env_windows.c",
+        "src/core/lib/support/histogram.c",
+        "src/core/lib/support/host_port.c",
+        "src/core/lib/support/log.c",
+        "src/core/lib/support/log_android.c",
+        "src/core/lib/support/log_linux.c",
+        "src/core/lib/support/log_posix.c",
+        "src/core/lib/support/log_windows.c",
+        "src/core/lib/support/mpscq.c",
+        "src/core/lib/support/murmur_hash.c",
+        "src/core/lib/support/stack_lockfree.c",
+        "src/core/lib/support/string.c",
+        "src/core/lib/support/string_posix.c",
+        "src/core/lib/support/string_util_windows.c",
+        "src/core/lib/support/string_windows.c",
+        "src/core/lib/support/subprocess_posix.c",
+        "src/core/lib/support/subprocess_windows.c",
+        "src/core/lib/support/sync.c",
+        "src/core/lib/support/sync_posix.c",
+        "src/core/lib/support/sync_windows.c",
+        "src/core/lib/support/thd.c",
+        "src/core/lib/support/thd_posix.c",
+        "src/core/lib/support/thd_windows.c",
+        "src/core/lib/support/time.c",
+        "src/core/lib/support/time_posix.c",
+        "src/core/lib/support/time_precise.c",
+        "src/core/lib/support/time_windows.c",
+        "src/core/lib/support/tls_pthread.c",
+        "src/core/lib/support/tmpfile_msys.c",
+        "src/core/lib/support/tmpfile_posix.c",
+        "src/core/lib/support/tmpfile_windows.c",
+        "src/core/lib/support/wrap_memcpy.c",
+    ],
+    hdrs = [
+        "src/core/lib/profiling/timers.h",
+        "src/core/lib/support/backoff.h",
+        "src/core/lib/support/block_annotate.h",
+        "src/core/lib/support/env.h",
+        "src/core/lib/support/mpscq.h",
+        "src/core/lib/support/murmur_hash.h",
+        "src/core/lib/support/stack_lockfree.h",
+        "src/core/lib/support/string.h",
+        "src/core/lib/support/string_windows.h",
+        "src/core/lib/support/thd_internal.h",
+        "src/core/lib/support/time_precise.h",
+        "src/core/lib/support/tmpfile.h",
+    ],
+    language = "c",
+    public_hdrs = [
+        "include/grpc/support/alloc.h",
+        "include/grpc/support/atm.h",
+        "include/grpc/support/atm_gcc_atomic.h",
+        "include/grpc/support/atm_gcc_sync.h",
+        "include/grpc/support/atm_windows.h",
+        "include/grpc/support/avl.h",
+        "include/grpc/support/cmdline.h",
+        "include/grpc/support/cpu.h",
+        "include/grpc/support/histogram.h",
+        "include/grpc/support/host_port.h",
+        "include/grpc/support/log.h",
+        "include/grpc/support/log_windows.h",
+        "include/grpc/support/port_platform.h",
+        "include/grpc/support/string_util.h",
+        "include/grpc/support/subprocess.h",
+        "include/grpc/support/sync.h",
+        "include/grpc/support/sync_generic.h",
+        "include/grpc/support/sync_posix.h",
+        "include/grpc/support/sync_windows.h",
+        "include/grpc/support/thd.h",
+        "include/grpc/support/time.h",
+        "include/grpc/support/tls.h",
+        "include/grpc/support/tls_gcc.h",
+        "include/grpc/support/tls_msvc.h",
+        "include/grpc/support/tls_pthread.h",
+        "include/grpc/support/useful.h",
+    ],
+    deps = [
+        "gpr_codegen",
+    ],
+)
+
+grpc_cc_library(
+    name = "gpr_codegen",
+    language = "c",
+    public_hdrs = [
+        "include/grpc/impl/codegen/atm.h",
+        "include/grpc/impl/codegen/atm_gcc_atomic.h",
+        "include/grpc/impl/codegen/atm_gcc_sync.h",
+        "include/grpc/impl/codegen/atm_windows.h",
+        "include/grpc/impl/codegen/gpr_types.h",
+        "include/grpc/impl/codegen/port_platform.h",
+        "include/grpc/impl/codegen/slice.h",
+        "include/grpc/impl/codegen/sync.h",
+        "include/grpc/impl/codegen/sync_generic.h",
+        "include/grpc/impl/codegen/sync_posix.h",
+        "include/grpc/impl/codegen/sync_windows.h",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_base",
+    srcs = [
+        "src/core/lib/channel/channel_args.c",
+        "src/core/lib/channel/channel_stack.c",
+        "src/core/lib/channel/channel_stack_builder.c",
+        "src/core/lib/channel/compress_filter.c",
+        "src/core/lib/channel/connected_channel.c",
+        "src/core/lib/channel/deadline_filter.c",
+        "src/core/lib/channel/handshaker.c",
+        "src/core/lib/channel/handshaker_factory.c",
+        "src/core/lib/channel/handshaker_registry.c",
+        "src/core/lib/channel/http_client_filter.c",
+        "src/core/lib/channel/http_server_filter.c",
+        "src/core/lib/channel/message_size_filter.c",
+        "src/core/lib/compression/compression.c",
+        "src/core/lib/compression/message_compress.c",
+        "src/core/lib/debug/trace.c",
+        "src/core/lib/http/format_request.c",
+        "src/core/lib/http/httpcli.c",
+        "src/core/lib/http/parser.c",
+        "src/core/lib/iomgr/closure.c",
+        "src/core/lib/iomgr/combiner.c",
+        "src/core/lib/iomgr/endpoint.c",
+        "src/core/lib/iomgr/endpoint_pair_posix.c",
+        "src/core/lib/iomgr/endpoint_pair_uv.c",
+        "src/core/lib/iomgr/endpoint_pair_windows.c",
+        "src/core/lib/iomgr/error.c",
+        "src/core/lib/iomgr/ev_epoll_linux.c",
+        "src/core/lib/iomgr/ev_poll_posix.c",
+        "src/core/lib/iomgr/ev_posix.c",
+        "src/core/lib/iomgr/exec_ctx.c",
+        "src/core/lib/iomgr/executor.c",
+        "src/core/lib/iomgr/iocp_windows.c",
+        "src/core/lib/iomgr/iomgr.c",
+        "src/core/lib/iomgr/iomgr_posix.c",
+        "src/core/lib/iomgr/iomgr_uv.c",
+        "src/core/lib/iomgr/iomgr_windows.c",
+        "src/core/lib/iomgr/load_file.c",
+        "src/core/lib/iomgr/network_status_tracker.c",
+        "src/core/lib/iomgr/polling_entity.c",
+        "src/core/lib/iomgr/pollset_set_uv.c",
+        "src/core/lib/iomgr/pollset_set_windows.c",
+        "src/core/lib/iomgr/pollset_uv.c",
+        "src/core/lib/iomgr/pollset_windows.c",
+        "src/core/lib/iomgr/resolve_address_posix.c",
+        "src/core/lib/iomgr/resolve_address_uv.c",
+        "src/core/lib/iomgr/resolve_address_windows.c",
+        "src/core/lib/iomgr/resource_quota.c",
+        "src/core/lib/iomgr/sockaddr_utils.c",
+        "src/core/lib/iomgr/socket_mutator.c",
+        "src/core/lib/iomgr/socket_utils_common_posix.c",
+        "src/core/lib/iomgr/socket_utils_linux.c",
+        "src/core/lib/iomgr/socket_utils_posix.c",
+        "src/core/lib/iomgr/socket_utils_uv.c",
+        "src/core/lib/iomgr/socket_utils_windows.c",
+        "src/core/lib/iomgr/socket_windows.c",
+        "src/core/lib/iomgr/tcp_client_posix.c",
+        "src/core/lib/iomgr/tcp_client_uv.c",
+        "src/core/lib/iomgr/tcp_client_windows.c",
+        "src/core/lib/iomgr/tcp_posix.c",
+        "src/core/lib/iomgr/tcp_server_posix.c",
+        "src/core/lib/iomgr/tcp_server_uv.c",
+        "src/core/lib/iomgr/tcp_server_windows.c",
+        "src/core/lib/iomgr/tcp_uv.c",
+        "src/core/lib/iomgr/tcp_windows.c",
+        "src/core/lib/iomgr/time_averaged_stats.c",
+        "src/core/lib/iomgr/timer_generic.c",
+        "src/core/lib/iomgr/timer_heap.c",
+        "src/core/lib/iomgr/timer_uv.c",
+        "src/core/lib/iomgr/udp_server.c",
+        "src/core/lib/iomgr/unix_sockets_posix.c",
+        "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+        "src/core/lib/iomgr/wakeup_fd_cv.c",
+        "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+        "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+        "src/core/lib/iomgr/wakeup_fd_pipe.c",
+        "src/core/lib/iomgr/wakeup_fd_posix.c",
+        "src/core/lib/iomgr/workqueue_uv.c",
+        "src/core/lib/iomgr/workqueue_windows.c",
+        "src/core/lib/json/json.c",
+        "src/core/lib/json/json_reader.c",
+        "src/core/lib/json/json_string.c",
+        "src/core/lib/json/json_writer.c",
+        "src/core/lib/slice/percent_encoding.c",
+        "src/core/lib/slice/slice.c",
+        "src/core/lib/slice/slice_buffer.c",
+        "src/core/lib/slice/slice_string_helpers.c",
+        "src/core/lib/surface/alarm.c",
+        "src/core/lib/surface/api_trace.c",
+        "src/core/lib/surface/byte_buffer.c",
+        "src/core/lib/surface/byte_buffer_reader.c",
+        "src/core/lib/surface/call.c",
+        "src/core/lib/surface/call_details.c",
+        "src/core/lib/surface/call_log_batch.c",
+        "src/core/lib/surface/channel.c",
+        "src/core/lib/surface/channel_init.c",
+        "src/core/lib/surface/channel_ping.c",
+        "src/core/lib/surface/channel_stack_type.c",
+        "src/core/lib/surface/completion_queue.c",
+        "src/core/lib/surface/event_string.c",
+        "src/core/lib/surface/lame_client.c",
+        "src/core/lib/surface/metadata_array.c",
+        "src/core/lib/surface/server.c",
+        "src/core/lib/surface/validate_metadata.c",
+        "src/core/lib/surface/version.c",
+        "src/core/lib/transport/byte_stream.c",
+        "src/core/lib/transport/connectivity_state.c",
+        "src/core/lib/transport/mdstr_hash_table.c",
+        "src/core/lib/transport/metadata.c",
+        "src/core/lib/transport/metadata_batch.c",
+        "src/core/lib/transport/pid_controller.c",
+        "src/core/lib/transport/service_config.c",
+        "src/core/lib/transport/static_metadata.c",
+        "src/core/lib/transport/timeout_encoding.c",
+        "src/core/lib/transport/transport.c",
+        "src/core/lib/transport/transport_op_string.c",
+    ],
+    hdrs = [
+        "src/core/lib/channel/channel_args.h",
+        "src/core/lib/channel/channel_stack.h",
+        "src/core/lib/channel/channel_stack_builder.h",
+        "src/core/lib/channel/compress_filter.h",
+        "src/core/lib/channel/connected_channel.h",
+        "src/core/lib/channel/context.h",
+        "src/core/lib/channel/deadline_filter.h",
+        "src/core/lib/channel/handshaker.h",
+        "src/core/lib/channel/handshaker_factory.h",
+        "src/core/lib/channel/handshaker_registry.h",
+        "src/core/lib/channel/http_client_filter.h",
+        "src/core/lib/channel/http_server_filter.h",
+        "src/core/lib/channel/message_size_filter.h",
+        "src/core/lib/compression/algorithm_metadata.h",
+        "src/core/lib/compression/message_compress.h",
+        "src/core/lib/debug/trace.h",
+        "src/core/lib/http/format_request.h",
+        "src/core/lib/http/httpcli.h",
+        "src/core/lib/http/parser.h",
+        "src/core/lib/iomgr/closure.h",
+        "src/core/lib/iomgr/combiner.h",
+        "src/core/lib/iomgr/endpoint.h",
+        "src/core/lib/iomgr/endpoint_pair.h",
+        "src/core/lib/iomgr/error.h",
+        "src/core/lib/iomgr/ev_epoll_linux.h",
+        "src/core/lib/iomgr/ev_poll_posix.h",
+        "src/core/lib/iomgr/ev_posix.h",
+        "src/core/lib/iomgr/exec_ctx.h",
+        "src/core/lib/iomgr/executor.h",
+        "src/core/lib/iomgr/iocp_windows.h",
+        "src/core/lib/iomgr/iomgr.h",
+        "src/core/lib/iomgr/iomgr_internal.h",
+        "src/core/lib/iomgr/iomgr_posix.h",
+        "src/core/lib/iomgr/load_file.h",
+        "src/core/lib/iomgr/network_status_tracker.h",
+        "src/core/lib/iomgr/polling_entity.h",
+        "src/core/lib/iomgr/pollset.h",
+        "src/core/lib/iomgr/pollset_set.h",
+        "src/core/lib/iomgr/pollset_set_windows.h",
+        "src/core/lib/iomgr/pollset_uv.h",
+        "src/core/lib/iomgr/pollset_windows.h",
+        "src/core/lib/iomgr/port.h",
+        "src/core/lib/iomgr/resolve_address.h",
+        "src/core/lib/iomgr/resource_quota.h",
+        "src/core/lib/iomgr/sockaddr.h",
+        "src/core/lib/iomgr/sockaddr_posix.h",
+        "src/core/lib/iomgr/sockaddr_utils.h",
+        "src/core/lib/iomgr/sockaddr_windows.h",
+        "src/core/lib/iomgr/socket_mutator.h",
+        "src/core/lib/iomgr/socket_utils.h",
+        "src/core/lib/iomgr/socket_utils_posix.h",
+        "src/core/lib/iomgr/socket_windows.h",
+        "src/core/lib/iomgr/tcp_client.h",
+        "src/core/lib/iomgr/tcp_client_posix.h",
+        "src/core/lib/iomgr/tcp_posix.h",
+        "src/core/lib/iomgr/tcp_server.h",
+        "src/core/lib/iomgr/tcp_uv.h",
+        "src/core/lib/iomgr/tcp_windows.h",
+        "src/core/lib/iomgr/time_averaged_stats.h",
+        "src/core/lib/iomgr/timer.h",
+        "src/core/lib/iomgr/timer_generic.h",
+        "src/core/lib/iomgr/timer_heap.h",
+        "src/core/lib/iomgr/timer_uv.h",
+        "src/core/lib/iomgr/udp_server.h",
+        "src/core/lib/iomgr/unix_sockets_posix.h",
+        "src/core/lib/iomgr/wakeup_fd_cv.h",
+        "src/core/lib/iomgr/wakeup_fd_pipe.h",
+        "src/core/lib/iomgr/wakeup_fd_posix.h",
+        "src/core/lib/iomgr/workqueue.h",
+        "src/core/lib/iomgr/workqueue_uv.h",
+        "src/core/lib/iomgr/workqueue_windows.h",
+        "src/core/lib/json/json.h",
+        "src/core/lib/json/json_common.h",
+        "src/core/lib/json/json_reader.h",
+        "src/core/lib/json/json_writer.h",
+        "src/core/lib/slice/percent_encoding.h",
+        "src/core/lib/slice/slice_internal.h",
+        "src/core/lib/slice/slice_string_helpers.h",
+        "src/core/lib/surface/api_trace.h",
+        "src/core/lib/surface/call.h",
+        "src/core/lib/surface/call_test_only.h",
+        "src/core/lib/surface/channel.h",
+        "src/core/lib/surface/channel_init.h",
+        "src/core/lib/surface/channel_stack_type.h",
+        "src/core/lib/surface/completion_queue.h",
+        "src/core/lib/surface/event_string.h",
+        "src/core/lib/surface/init.h",
+        "src/core/lib/surface/lame_client.h",
+        "src/core/lib/surface/server.h",
+        "src/core/lib/transport/byte_stream.h",
+        "src/core/lib/transport/connectivity_state.h",
+        "src/core/lib/transport/mdstr_hash_table.h",
+        "src/core/lib/transport/metadata.h",
+        "src/core/lib/transport/metadata_batch.h",
+        "src/core/lib/transport/pid_controller.h",
+        "src/core/lib/transport/service_config.h",
+        "src/core/lib/transport/static_metadata.h",
+        "src/core/lib/transport/timeout_encoding.h",
+        "src/core/lib/transport/transport.h",
+        "src/core/lib/transport/transport_impl.h",
+    ],
+    external_deps = [
+        "zlib",
+    ],
+    language = "c",
+    public_hdrs = [
+        "include/grpc/byte_buffer.h",
+        "include/grpc/byte_buffer_reader.h",
+        "include/grpc/compression.h",
+        "include/grpc/grpc.h",
+        "include/grpc/grpc_posix.h",
+        "include/grpc/grpc_security_constants.h",
+        "include/grpc/slice.h",
+        "include/grpc/slice_buffer.h",
+        "include/grpc/status.h",
+    ],
+    deps = [
+        "gpr_base",
+        "grpc_codegen",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_client_channel",
+    language = "c",
+    srcs = [
+        "src/core/ext/client_channel/channel_connectivity.c",
+        "src/core/ext/client_channel/client_channel.c",
+        "src/core/ext/client_channel/client_channel_factory.c",
+        "src/core/ext/client_channel/client_channel_plugin.c",
+        "src/core/ext/client_channel/connector.c",
+        "src/core/ext/client_channel/default_initial_connect_string.c",
+        "src/core/ext/client_channel/http_connect_handshaker.c",
+        "src/core/ext/client_channel/initial_connect_string.c",
+        "src/core/ext/client_channel/lb_policy.c",
+        "src/core/ext/client_channel/lb_policy_factory.c",
+        "src/core/ext/client_channel/lb_policy_registry.c",
+        "src/core/ext/client_channel/parse_address.c",
+        "src/core/ext/client_channel/resolver.c",
+        "src/core/ext/client_channel/resolver_factory.c",
+        "src/core/ext/client_channel/resolver_registry.c",
+        "src/core/ext/client_channel/subchannel.c",
+        "src/core/ext/client_channel/subchannel_index.c",
+        "src/core/ext/client_channel/uri_parser.c",
+    ],
+    hdrs = [
+        "src/core/ext/client_channel/client_channel.h",
+        "src/core/ext/client_channel/client_channel_factory.h",
+        "src/core/ext/client_channel/connector.h",
+        "src/core/ext/client_channel/http_connect_handshaker.h",
+        "src/core/ext/client_channel/initial_connect_string.h",
+        "src/core/ext/client_channel/lb_policy.h",
+        "src/core/ext/client_channel/lb_policy_factory.h",
+        "src/core/ext/client_channel/lb_policy_registry.h",
+        "src/core/ext/client_channel/parse_address.h",
+        "src/core/ext/client_channel/resolver.h",
+        "src/core/ext/client_channel/resolver_factory.h",
+        "src/core/ext/client_channel/resolver_registry.h",
+        "src/core/ext/client_channel/subchannel.h",
+        "src/core/ext/client_channel/subchannel_index.h",
+        "src/core/ext/client_channel/uri_parser.h",
+    ],
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_codegen",
+    language = "c",
+    public_hdrs = [
+        "include/grpc/impl/codegen/byte_buffer_reader.h",
+        "include/grpc/impl/codegen/compression_types.h",
+        "include/grpc/impl/codegen/connectivity_state.h",
+        "include/grpc/impl/codegen/exec_ctx_fwd.h",
+        "include/grpc/impl/codegen/grpc_types.h",
+        "include/grpc/impl/codegen/propagation_bits.h",
+        "include/grpc/impl/codegen/status.h",
+    ],
+    deps = [
+        "gpr_codegen",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_lb_policy_grpclb",
+    srcs = [
+        "src/core/ext/lb_policy/grpclb/grpclb.c",
+        "src/core/ext/lb_policy/grpclb/load_balancer_api.c",
+        "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
+    ],
+    hdrs = [
+        "src/core/ext/lb_policy/grpclb/grpclb.h",
+        "src/core/ext/lb_policy/grpclb/load_balancer_api.h",
+        "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
+    ],
+    external_deps = [
+        "nanopb",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_lb_policy_pick_first",
+    srcs = [
+        "src/core/ext/lb_policy/pick_first/pick_first.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_lb_policy_round_robin",
+    srcs = [
+        "src/core/ext/lb_policy/round_robin/round_robin.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_load_reporting",
+    srcs = [
+        "src/core/ext/load_reporting/load_reporting.c",
+        "src/core/ext/load_reporting/load_reporting_filter.c",
+    ],
+    hdrs = [
+        "src/core/ext/load_reporting/load_reporting.h",
+        "src/core/ext/load_reporting/load_reporting_filter.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_resolver_dns_native",
+    srcs = [
+        "src/core/ext/resolver/dns/native/dns_resolver.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_resolver_sockaddr",
+    srcs = [
+        "src/core/ext/resolver/sockaddr/sockaddr_resolver.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_secure",
+    srcs = [
+        "src/core/lib/http/httpcli_security_connector.c",
+        "src/core/lib/security/context/security_context.c",
+        "src/core/lib/security/credentials/composite/composite_credentials.c",
+        "src/core/lib/security/credentials/credentials.c",
+        "src/core/lib/security/credentials/credentials_metadata.c",
+        "src/core/lib/security/credentials/fake/fake_credentials.c",
+        "src/core/lib/security/credentials/google_default/credentials_generic.c",
+        "src/core/lib/security/credentials/google_default/google_default_credentials.c",
+        "src/core/lib/security/credentials/iam/iam_credentials.c",
+        "src/core/lib/security/credentials/jwt/json_token.c",
+        "src/core/lib/security/credentials/jwt/jwt_credentials.c",
+        "src/core/lib/security/credentials/jwt/jwt_verifier.c",
+        "src/core/lib/security/credentials/oauth2/oauth2_credentials.c",
+        "src/core/lib/security/credentials/plugin/plugin_credentials.c",
+        "src/core/lib/security/credentials/ssl/ssl_credentials.c",
+        "src/core/lib/security/transport/client_auth_filter.c",
+        "src/core/lib/security/transport/secure_endpoint.c",
+        "src/core/lib/security/transport/security_connector.c",
+        "src/core/lib/security/transport/security_handshaker.c",
+        "src/core/lib/security/transport/server_auth_filter.c",
+        "src/core/lib/security/transport/tsi_error.c",
+        "src/core/lib/security/util/b64.c",
+        "src/core/lib/security/util/json_util.c",
+        "src/core/lib/surface/init_secure.c",
+    ],
+    hdrs = [
+        "src/core/lib/security/context/security_context.h",
+        "src/core/lib/security/credentials/composite/composite_credentials.h",
+        "src/core/lib/security/credentials/credentials.h",
+        "src/core/lib/security/credentials/fake/fake_credentials.h",
+        "src/core/lib/security/credentials/google_default/google_default_credentials.h",
+        "src/core/lib/security/credentials/iam/iam_credentials.h",
+        "src/core/lib/security/credentials/jwt/json_token.h",
+        "src/core/lib/security/credentials/jwt/jwt_credentials.h",
+        "src/core/lib/security/credentials/jwt/jwt_verifier.h",
+        "src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
+        "src/core/lib/security/credentials/plugin/plugin_credentials.h",
+        "src/core/lib/security/credentials/ssl/ssl_credentials.h",
+        "src/core/lib/security/transport/auth_filters.h",
+        "src/core/lib/security/transport/secure_endpoint.h",
+        "src/core/lib/security/transport/security_connector.h",
+        "src/core/lib/security/transport/security_handshaker.h",
+        "src/core/lib/security/transport/tsi_error.h",
+        "src/core/lib/security/util/b64.h",
+        "src/core/lib/security/util/json_util.h",
+    ],
+    language = "c",
+    public_hdrs = [
+        "include/grpc/grpc_security.h",
+    ],
+    deps = [
+        "grpc_base",
+        "grpc_transport_chttp2_alpn",
+        "tsi",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_transport_chttp2",
+    srcs = [
+        "src/core/ext/transport/chttp2/transport/bin_decoder.c",
+        "src/core/ext/transport/chttp2/transport/bin_encoder.c",
+        "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
+        "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
+        "src/core/ext/transport/chttp2/transport/frame_data.c",
+        "src/core/ext/transport/chttp2/transport/frame_goaway.c",
+        "src/core/ext/transport/chttp2/transport/frame_ping.c",
+        "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
+        "src/core/ext/transport/chttp2/transport/frame_settings.c",
+        "src/core/ext/transport/chttp2/transport/frame_window_update.c",
+        "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
+        "src/core/ext/transport/chttp2/transport/hpack_parser.c",
+        "src/core/ext/transport/chttp2/transport/hpack_table.c",
+        "src/core/ext/transport/chttp2/transport/huffsyms.c",
+        "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
+        "src/core/ext/transport/chttp2/transport/parsing.c",
+        "src/core/ext/transport/chttp2/transport/status_conversion.c",
+        "src/core/ext/transport/chttp2/transport/stream_lists.c",
+        "src/core/ext/transport/chttp2/transport/stream_map.c",
+        "src/core/ext/transport/chttp2/transport/varint.c",
+        "src/core/ext/transport/chttp2/transport/writing.c",
+    ],
+    hdrs = [
+        "src/core/ext/transport/chttp2/transport/bin_decoder.h",
+        "src/core/ext/transport/chttp2/transport/bin_encoder.h",
+        "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
+        "src/core/ext/transport/chttp2/transport/frame.h",
+        "src/core/ext/transport/chttp2/transport/frame_data.h",
+        "src/core/ext/transport/chttp2/transport/frame_goaway.h",
+        "src/core/ext/transport/chttp2/transport/frame_ping.h",
+        "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
+        "src/core/ext/transport/chttp2/transport/frame_settings.h",
+        "src/core/ext/transport/chttp2/transport/frame_window_update.h",
+        "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
+        "src/core/ext/transport/chttp2/transport/hpack_parser.h",
+        "src/core/ext/transport/chttp2/transport/hpack_table.h",
+        "src/core/ext/transport/chttp2/transport/http2_errors.h",
+        "src/core/ext/transport/chttp2/transport/huffsyms.h",
+        "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
+        "src/core/ext/transport/chttp2/transport/internal.h",
+        "src/core/ext/transport/chttp2/transport/status_conversion.h",
+        "src/core/ext/transport/chttp2/transport/stream_map.h",
+        "src/core/ext/transport/chttp2/transport/varint.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_transport_chttp2_alpn",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_transport_chttp2_alpn",
+    srcs = [
+        "src/core/ext/transport/chttp2/alpn/alpn.c",
+    ],
+    hdrs = [
+        "src/core/ext/transport/chttp2/alpn/alpn.h",
+    ],
+    language = "c",
+    deps = [
+        "gpr",
+    ],
+)
+
+grpc_cc_library(
+  name = "grpc_transport_chttp2_client_connector",
   hdrs = [
-    "include/grpc/support/alloc.h",
-    "include/grpc/support/atm.h",
-    "include/grpc/support/atm_gcc_atomic.h",
-    "include/grpc/support/atm_gcc_sync.h",
-    "include/grpc/support/atm_windows.h",
-    "include/grpc/support/avl.h",
-    "include/grpc/support/cmdline.h",
-    "include/grpc/support/cpu.h",
-    "include/grpc/support/histogram.h",
-    "include/grpc/support/host_port.h",
-    "include/grpc/support/log.h",
-    "include/grpc/support/log_windows.h",
-    "include/grpc/support/port_platform.h",
-    "include/grpc/support/string_util.h",
-    "include/grpc/support/subprocess.h",
-    "include/grpc/support/sync.h",
-    "include/grpc/support/sync_generic.h",
-    "include/grpc/support/sync_posix.h",
-    "include/grpc/support/sync_windows.h",
-    "include/grpc/support/thd.h",
-    "include/grpc/support/time.h",
-    "include/grpc/support/tls.h",
-    "include/grpc/support/tls_gcc.h",
-    "include/grpc/support/tls_msvc.h",
-    "include/grpc/support/tls_pthread.h",
-    "include/grpc/support/useful.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
+   "src/core/ext/transport/chttp2/client/chttp2_connector.h",
   ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-  ],
-)
-
-
-
-cc_library(
-  name = "grpc",
   srcs = [
-    "src/core/lib/channel/channel_args.h",
-    "src/core/lib/channel/channel_stack.h",
-    "src/core/lib/channel/channel_stack_builder.h",
-    "src/core/lib/channel/compress_filter.h",
-    "src/core/lib/channel/connected_channel.h",
-    "src/core/lib/channel/context.h",
-    "src/core/lib/channel/deadline_filter.h",
-    "src/core/lib/channel/handshaker.h",
-    "src/core/lib/channel/http_client_filter.h",
-    "src/core/lib/channel/http_server_filter.h",
-    "src/core/lib/channel/message_size_filter.h",
-    "src/core/lib/compression/algorithm_metadata.h",
-    "src/core/lib/compression/message_compress.h",
-    "src/core/lib/debug/trace.h",
-    "src/core/lib/http/format_request.h",
-    "src/core/lib/http/httpcli.h",
-    "src/core/lib/http/parser.h",
-    "src/core/lib/iomgr/closure.h",
-    "src/core/lib/iomgr/combiner.h",
-    "src/core/lib/iomgr/endpoint.h",
-    "src/core/lib/iomgr/endpoint_pair.h",
-    "src/core/lib/iomgr/error.h",
-    "src/core/lib/iomgr/ev_epoll_linux.h",
-    "src/core/lib/iomgr/ev_poll_posix.h",
-    "src/core/lib/iomgr/ev_posix.h",
-    "src/core/lib/iomgr/exec_ctx.h",
-    "src/core/lib/iomgr/executor.h",
-    "src/core/lib/iomgr/iocp_windows.h",
-    "src/core/lib/iomgr/iomgr.h",
-    "src/core/lib/iomgr/iomgr_internal.h",
-    "src/core/lib/iomgr/iomgr_posix.h",
-    "src/core/lib/iomgr/load_file.h",
-    "src/core/lib/iomgr/network_status_tracker.h",
-    "src/core/lib/iomgr/polling_entity.h",
-    "src/core/lib/iomgr/pollset.h",
-    "src/core/lib/iomgr/pollset_set.h",
-    "src/core/lib/iomgr/pollset_set_windows.h",
-    "src/core/lib/iomgr/pollset_uv.h",
-    "src/core/lib/iomgr/pollset_windows.h",
-    "src/core/lib/iomgr/port.h",
-    "src/core/lib/iomgr/resolve_address.h",
-    "src/core/lib/iomgr/resource_quota.h",
-    "src/core/lib/iomgr/sockaddr.h",
-    "src/core/lib/iomgr/sockaddr_posix.h",
-    "src/core/lib/iomgr/sockaddr_utils.h",
-    "src/core/lib/iomgr/sockaddr_windows.h",
-    "src/core/lib/iomgr/socket_mutator.h",
-    "src/core/lib/iomgr/socket_utils.h",
-    "src/core/lib/iomgr/socket_utils_posix.h",
-    "src/core/lib/iomgr/socket_windows.h",
-    "src/core/lib/iomgr/tcp_client.h",
-    "src/core/lib/iomgr/tcp_client_posix.h",
-    "src/core/lib/iomgr/tcp_posix.h",
-    "src/core/lib/iomgr/tcp_server.h",
-    "src/core/lib/iomgr/tcp_uv.h",
-    "src/core/lib/iomgr/tcp_windows.h",
-    "src/core/lib/iomgr/time_averaged_stats.h",
-    "src/core/lib/iomgr/timer.h",
-    "src/core/lib/iomgr/timer_generic.h",
-    "src/core/lib/iomgr/timer_heap.h",
-    "src/core/lib/iomgr/timer_uv.h",
-    "src/core/lib/iomgr/udp_server.h",
-    "src/core/lib/iomgr/unix_sockets_posix.h",
-    "src/core/lib/iomgr/wakeup_fd_cv.h",
-    "src/core/lib/iomgr/wakeup_fd_pipe.h",
-    "src/core/lib/iomgr/wakeup_fd_posix.h",
-    "src/core/lib/iomgr/workqueue.h",
-    "src/core/lib/iomgr/workqueue_uv.h",
-    "src/core/lib/iomgr/workqueue_windows.h",
-    "src/core/lib/json/json.h",
-    "src/core/lib/json/json_common.h",
-    "src/core/lib/json/json_reader.h",
-    "src/core/lib/json/json_writer.h",
-    "src/core/lib/slice/percent_encoding.h",
-    "src/core/lib/slice/slice_string_helpers.h",
-    "src/core/lib/surface/api_trace.h",
-    "src/core/lib/surface/call.h",
-    "src/core/lib/surface/call_test_only.h",
-    "src/core/lib/surface/channel.h",
-    "src/core/lib/surface/channel_init.h",
-    "src/core/lib/surface/channel_stack_type.h",
-    "src/core/lib/surface/completion_queue.h",
-    "src/core/lib/surface/event_string.h",
-    "src/core/lib/surface/init.h",
-    "src/core/lib/surface/lame_client.h",
-    "src/core/lib/surface/server.h",
-    "src/core/lib/transport/byte_stream.h",
-    "src/core/lib/transport/connectivity_state.h",
-    "src/core/lib/transport/mdstr_hash_table.h",
-    "src/core/lib/transport/metadata.h",
-    "src/core/lib/transport/metadata_batch.h",
-    "src/core/lib/transport/pid_controller.h",
-    "src/core/lib/transport/service_config.h",
-    "src/core/lib/transport/static_metadata.h",
-    "src/core/lib/transport/timeout_encoding.h",
-    "src/core/lib/transport/transport.h",
-    "src/core/lib/transport/transport_impl.h",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.h",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
-    "src/core/ext/transport/chttp2/transport/frame.h",
-    "src/core/ext/transport/chttp2/transport/frame_data.h",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
-    "src/core/ext/transport/chttp2/transport/frame_ping.h",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
-    "src/core/ext/transport/chttp2/transport/frame_settings.h",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
-    "src/core/ext/transport/chttp2/transport/hpack_table.h",
-    "src/core/ext/transport/chttp2/transport/http2_errors.h",
-    "src/core/ext/transport/chttp2/transport/huffsyms.h",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
-    "src/core/ext/transport/chttp2/transport/internal.h",
-    "src/core/ext/transport/chttp2/transport/status_conversion.h",
-    "src/core/ext/transport/chttp2/transport/stream_map.h",
-    "src/core/ext/transport/chttp2/transport/varint.h",
-    "src/core/ext/transport/chttp2/alpn/alpn.h",
-    "src/core/lib/security/context/security_context.h",
-    "src/core/lib/security/credentials/composite/composite_credentials.h",
-    "src/core/lib/security/credentials/credentials.h",
-    "src/core/lib/security/credentials/fake/fake_credentials.h",
-    "src/core/lib/security/credentials/google_default/google_default_credentials.h",
-    "src/core/lib/security/credentials/iam/iam_credentials.h",
-    "src/core/lib/security/credentials/jwt/json_token.h",
-    "src/core/lib/security/credentials/jwt/jwt_credentials.h",
-    "src/core/lib/security/credentials/jwt/jwt_verifier.h",
-    "src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
-    "src/core/lib/security/credentials/plugin/plugin_credentials.h",
-    "src/core/lib/security/credentials/ssl/ssl_credentials.h",
-    "src/core/lib/security/transport/auth_filters.h",
-    "src/core/lib/security/transport/secure_endpoint.h",
-    "src/core/lib/security/transport/security_connector.h",
-    "src/core/lib/security/transport/security_handshaker.h",
-    "src/core/lib/security/transport/tsi_error.h",
-    "src/core/lib/security/util/b64.h",
-    "src/core/lib/security/util/json_util.h",
-    "src/core/lib/tsi/fake_transport_security.h",
-    "src/core/lib/tsi/ssl_transport_security.h",
-    "src/core/lib/tsi/ssl_types.h",
-    "src/core/lib/tsi/transport_security.h",
-    "src/core/lib/tsi/transport_security_interface.h",
-    "src/core/ext/transport/chttp2/server/chttp2_server.h",
-    "src/core/ext/client_channel/client_channel.h",
-    "src/core/ext/client_channel/client_channel_factory.h",
-    "src/core/ext/client_channel/connector.h",
-    "src/core/ext/client_channel/http_connect_handshaker.h",
-    "src/core/ext/client_channel/initial_connect_string.h",
-    "src/core/ext/client_channel/lb_policy.h",
-    "src/core/ext/client_channel/lb_policy_factory.h",
-    "src/core/ext/client_channel/lb_policy_registry.h",
-    "src/core/ext/client_channel/parse_address.h",
-    "src/core/ext/client_channel/resolver.h",
-    "src/core/ext/client_channel/resolver_factory.h",
-    "src/core/ext/client_channel/resolver_registry.h",
-    "src/core/ext/client_channel/subchannel.h",
-    "src/core/ext/client_channel/subchannel_index.h",
-    "src/core/ext/client_channel/uri_parser.h",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.h",
-    "src/core/ext/lb_policy/grpclb/grpclb.h",
-    "src/core/ext/lb_policy/grpclb/load_balancer_api.h",
-    "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
-    "src/core/ext/load_reporting/load_reporting.h",
-    "src/core/ext/load_reporting/load_reporting_filter.h",
-    "src/core/ext/census/aggregation.h",
-    "src/core/ext/census/base_resources.h",
-    "src/core/ext/census/census_interface.h",
-    "src/core/ext/census/census_rpc_stats.h",
-    "src/core/ext/census/gen/census.pb.h",
-    "src/core/ext/census/gen/trace_context.pb.h",
-    "src/core/ext/census/grpc_filter.h",
-    "src/core/ext/census/mlog.h",
-    "src/core/ext/census/resource.h",
-    "src/core/ext/census/rpc_metric_id.h",
-    "src/core/ext/census/trace_context.h",
-    "src/core/lib/surface/init.c",
-    "src/core/lib/channel/channel_args.c",
-    "src/core/lib/channel/channel_stack.c",
-    "src/core/lib/channel/channel_stack_builder.c",
-    "src/core/lib/channel/compress_filter.c",
-    "src/core/lib/channel/connected_channel.c",
-    "src/core/lib/channel/deadline_filter.c",
-    "src/core/lib/channel/handshaker.c",
-    "src/core/lib/channel/http_client_filter.c",
-    "src/core/lib/channel/http_server_filter.c",
-    "src/core/lib/channel/message_size_filter.c",
-    "src/core/lib/compression/compression.c",
-    "src/core/lib/compression/message_compress.c",
-    "src/core/lib/debug/trace.c",
-    "src/core/lib/http/format_request.c",
-    "src/core/lib/http/httpcli.c",
-    "src/core/lib/http/parser.c",
-    "src/core/lib/iomgr/closure.c",
-    "src/core/lib/iomgr/combiner.c",
-    "src/core/lib/iomgr/endpoint.c",
-    "src/core/lib/iomgr/endpoint_pair_posix.c",
-    "src/core/lib/iomgr/endpoint_pair_uv.c",
-    "src/core/lib/iomgr/endpoint_pair_windows.c",
-    "src/core/lib/iomgr/error.c",
-    "src/core/lib/iomgr/ev_epoll_linux.c",
-    "src/core/lib/iomgr/ev_poll_posix.c",
-    "src/core/lib/iomgr/ev_posix.c",
-    "src/core/lib/iomgr/exec_ctx.c",
-    "src/core/lib/iomgr/executor.c",
-    "src/core/lib/iomgr/iocp_windows.c",
-    "src/core/lib/iomgr/iomgr.c",
-    "src/core/lib/iomgr/iomgr_posix.c",
-    "src/core/lib/iomgr/iomgr_uv.c",
-    "src/core/lib/iomgr/iomgr_windows.c",
-    "src/core/lib/iomgr/load_file.c",
-    "src/core/lib/iomgr/network_status_tracker.c",
-    "src/core/lib/iomgr/polling_entity.c",
-    "src/core/lib/iomgr/pollset_set_uv.c",
-    "src/core/lib/iomgr/pollset_set_windows.c",
-    "src/core/lib/iomgr/pollset_uv.c",
-    "src/core/lib/iomgr/pollset_windows.c",
-    "src/core/lib/iomgr/resolve_address_posix.c",
-    "src/core/lib/iomgr/resolve_address_uv.c",
-    "src/core/lib/iomgr/resolve_address_windows.c",
-    "src/core/lib/iomgr/resource_quota.c",
-    "src/core/lib/iomgr/sockaddr_utils.c",
-    "src/core/lib/iomgr/socket_mutator.c",
-    "src/core/lib/iomgr/socket_utils_common_posix.c",
-    "src/core/lib/iomgr/socket_utils_linux.c",
-    "src/core/lib/iomgr/socket_utils_posix.c",
-    "src/core/lib/iomgr/socket_utils_uv.c",
-    "src/core/lib/iomgr/socket_utils_windows.c",
-    "src/core/lib/iomgr/socket_windows.c",
-    "src/core/lib/iomgr/tcp_client_posix.c",
-    "src/core/lib/iomgr/tcp_client_uv.c",
-    "src/core/lib/iomgr/tcp_client_windows.c",
-    "src/core/lib/iomgr/tcp_posix.c",
-    "src/core/lib/iomgr/tcp_server_posix.c",
-    "src/core/lib/iomgr/tcp_server_uv.c",
-    "src/core/lib/iomgr/tcp_server_windows.c",
-    "src/core/lib/iomgr/tcp_uv.c",
-    "src/core/lib/iomgr/tcp_windows.c",
-    "src/core/lib/iomgr/time_averaged_stats.c",
-    "src/core/lib/iomgr/timer_generic.c",
-    "src/core/lib/iomgr/timer_heap.c",
-    "src/core/lib/iomgr/timer_uv.c",
-    "src/core/lib/iomgr/udp_server.c",
-    "src/core/lib/iomgr/unix_sockets_posix.c",
-    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
-    "src/core/lib/iomgr/wakeup_fd_cv.c",
-    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
-    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
-    "src/core/lib/iomgr/wakeup_fd_pipe.c",
-    "src/core/lib/iomgr/wakeup_fd_posix.c",
-    "src/core/lib/iomgr/workqueue_uv.c",
-    "src/core/lib/iomgr/workqueue_windows.c",
-    "src/core/lib/json/json.c",
-    "src/core/lib/json/json_reader.c",
-    "src/core/lib/json/json_string.c",
-    "src/core/lib/json/json_writer.c",
-    "src/core/lib/slice/percent_encoding.c",
-    "src/core/lib/slice/slice.c",
-    "src/core/lib/slice/slice_buffer.c",
-    "src/core/lib/slice/slice_string_helpers.c",
-    "src/core/lib/surface/alarm.c",
-    "src/core/lib/surface/api_trace.c",
-    "src/core/lib/surface/byte_buffer.c",
-    "src/core/lib/surface/byte_buffer_reader.c",
-    "src/core/lib/surface/call.c",
-    "src/core/lib/surface/call_details.c",
-    "src/core/lib/surface/call_log_batch.c",
-    "src/core/lib/surface/channel.c",
-    "src/core/lib/surface/channel_init.c",
-    "src/core/lib/surface/channel_ping.c",
-    "src/core/lib/surface/channel_stack_type.c",
-    "src/core/lib/surface/completion_queue.c",
-    "src/core/lib/surface/event_string.c",
-    "src/core/lib/surface/lame_client.c",
-    "src/core/lib/surface/metadata_array.c",
-    "src/core/lib/surface/server.c",
-    "src/core/lib/surface/validate_metadata.c",
-    "src/core/lib/surface/version.c",
-    "src/core/lib/transport/byte_stream.c",
-    "src/core/lib/transport/connectivity_state.c",
-    "src/core/lib/transport/mdstr_hash_table.c",
-    "src/core/lib/transport/metadata.c",
-    "src/core/lib/transport/metadata_batch.c",
-    "src/core/lib/transport/pid_controller.c",
-    "src/core/lib/transport/service_config.c",
-    "src/core/lib/transport/static_metadata.c",
-    "src/core/lib/transport/timeout_encoding.c",
-    "src/core/lib/transport/transport.c",
-    "src/core/lib/transport/transport_op_string.c",
-    "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.c",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
-    "src/core/ext/transport/chttp2/transport/frame_data.c",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
-    "src/core/ext/transport/chttp2/transport/frame_ping.c",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
-    "src/core/ext/transport/chttp2/transport/frame_settings.c",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
-    "src/core/ext/transport/chttp2/transport/hpack_table.c",
-    "src/core/ext/transport/chttp2/transport/huffsyms.c",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
-    "src/core/ext/transport/chttp2/transport/parsing.c",
-    "src/core/ext/transport/chttp2/transport/status_conversion.c",
-    "src/core/ext/transport/chttp2/transport/stream_lists.c",
-    "src/core/ext/transport/chttp2/transport/stream_map.c",
-    "src/core/ext/transport/chttp2/transport/varint.c",
-    "src/core/ext/transport/chttp2/transport/writing.c",
-    "src/core/ext/transport/chttp2/alpn/alpn.c",
-    "src/core/lib/http/httpcli_security_connector.c",
-    "src/core/lib/security/context/security_context.c",
-    "src/core/lib/security/credentials/composite/composite_credentials.c",
-    "src/core/lib/security/credentials/credentials.c",
-    "src/core/lib/security/credentials/credentials_metadata.c",
-    "src/core/lib/security/credentials/fake/fake_credentials.c",
-    "src/core/lib/security/credentials/google_default/credentials_generic.c",
-    "src/core/lib/security/credentials/google_default/google_default_credentials.c",
-    "src/core/lib/security/credentials/iam/iam_credentials.c",
-    "src/core/lib/security/credentials/jwt/json_token.c",
-    "src/core/lib/security/credentials/jwt/jwt_credentials.c",
-    "src/core/lib/security/credentials/jwt/jwt_verifier.c",
-    "src/core/lib/security/credentials/oauth2/oauth2_credentials.c",
-    "src/core/lib/security/credentials/plugin/plugin_credentials.c",
-    "src/core/lib/security/credentials/ssl/ssl_credentials.c",
-    "src/core/lib/security/transport/client_auth_filter.c",
-    "src/core/lib/security/transport/secure_endpoint.c",
-    "src/core/lib/security/transport/security_connector.c",
-    "src/core/lib/security/transport/security_handshaker.c",
-    "src/core/lib/security/transport/server_auth_filter.c",
-    "src/core/lib/security/transport/tsi_error.c",
-    "src/core/lib/security/util/b64.c",
-    "src/core/lib/security/util/json_util.c",
-    "src/core/lib/surface/init_secure.c",
-    "src/core/lib/tsi/fake_transport_security.c",
-    "src/core/lib/tsi/ssl_transport_security.c",
-    "src/core/lib/tsi/transport_security.c",
-    "src/core/ext/transport/chttp2/server/chttp2_server.c",
-    "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
-    "src/core/ext/client_channel/channel_connectivity.c",
-    "src/core/ext/client_channel/client_channel.c",
-    "src/core/ext/client_channel/client_channel_factory.c",
-    "src/core/ext/client_channel/client_channel_plugin.c",
-    "src/core/ext/client_channel/connector.c",
-    "src/core/ext/client_channel/default_initial_connect_string.c",
-    "src/core/ext/client_channel/http_connect_handshaker.c",
-    "src/core/ext/client_channel/initial_connect_string.c",
-    "src/core/ext/client_channel/lb_policy.c",
-    "src/core/ext/client_channel/lb_policy_factory.c",
-    "src/core/ext/client_channel/lb_policy_registry.c",
-    "src/core/ext/client_channel/parse_address.c",
-    "src/core/ext/client_channel/resolver.c",
-    "src/core/ext/client_channel/resolver_factory.c",
-    "src/core/ext/client_channel/resolver_registry.c",
-    "src/core/ext/client_channel/subchannel.c",
-    "src/core/ext/client_channel/subchannel_index.c",
-    "src/core/ext/client_channel/uri_parser.c",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
-    "src/core/ext/lb_policy/grpclb/grpclb.c",
-    "src/core/ext/lb_policy/grpclb/load_balancer_api.c",
-    "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
-    "src/core/ext/lb_policy/pick_first/pick_first.c",
-    "src/core/ext/lb_policy/round_robin/round_robin.c",
-    "src/core/ext/resolver/dns/native/dns_resolver.c",
-    "src/core/ext/resolver/sockaddr/sockaddr_resolver.c",
-    "src/core/ext/load_reporting/load_reporting.c",
-    "src/core/ext/load_reporting/load_reporting_filter.c",
-    "src/core/ext/census/base_resources.c",
-    "src/core/ext/census/context.c",
-    "src/core/ext/census/gen/census.pb.c",
-    "src/core/ext/census/gen/trace_context.pb.c",
-    "src/core/ext/census/grpc_context.c",
-    "src/core/ext/census/grpc_filter.c",
-    "src/core/ext/census/grpc_plugin.c",
-    "src/core/ext/census/initialize.c",
-    "src/core/ext/census/mlog.c",
-    "src/core/ext/census/operation.c",
-    "src/core/ext/census/placeholders.c",
-    "src/core/ext/census/resource.c",
-    "src/core/ext/census/trace_context.c",
-    "src/core/ext/census/tracing.c",
-    "src/core/plugin_registry/grpc_plugin_registry.c",
+   "src/core/ext/transport/chttp2/client/chttp2_connector.c",
   ],
-  hdrs = [
-    "include/grpc/byte_buffer.h",
-    "include/grpc/byte_buffer_reader.h",
-    "include/grpc/compression.h",
-    "include/grpc/grpc.h",
-    "include/grpc/grpc_posix.h",
-    "include/grpc/grpc_security_constants.h",
-    "include/grpc/slice.h",
-    "include/grpc/slice_buffer.h",
-    "include/grpc/status.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/grpc_security.h",
-    "include/grpc/census.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
+  language = "c",
   deps = [
-    "//external:libssl",
-    "//external:zlib",
-    ":gpr",
-    "//external:nanopb",
-  ],
-  copts = [
-    "-std=gnu99",
+   "grpc_transport_chttp2",
+   "grpc_base",
+   "grpc_client_channel",
   ],
 )
 
 
-
-cc_library(
-  name = "grpc_cronet",
-  srcs = [
-    "src/core/lib/channel/channel_args.h",
-    "src/core/lib/channel/channel_stack.h",
-    "src/core/lib/channel/channel_stack_builder.h",
-    "src/core/lib/channel/compress_filter.h",
-    "src/core/lib/channel/connected_channel.h",
-    "src/core/lib/channel/context.h",
-    "src/core/lib/channel/deadline_filter.h",
-    "src/core/lib/channel/handshaker.h",
-    "src/core/lib/channel/http_client_filter.h",
-    "src/core/lib/channel/http_server_filter.h",
-    "src/core/lib/channel/message_size_filter.h",
-    "src/core/lib/compression/algorithm_metadata.h",
-    "src/core/lib/compression/message_compress.h",
-    "src/core/lib/debug/trace.h",
-    "src/core/lib/http/format_request.h",
-    "src/core/lib/http/httpcli.h",
-    "src/core/lib/http/parser.h",
-    "src/core/lib/iomgr/closure.h",
-    "src/core/lib/iomgr/combiner.h",
-    "src/core/lib/iomgr/endpoint.h",
-    "src/core/lib/iomgr/endpoint_pair.h",
-    "src/core/lib/iomgr/error.h",
-    "src/core/lib/iomgr/ev_epoll_linux.h",
-    "src/core/lib/iomgr/ev_poll_posix.h",
-    "src/core/lib/iomgr/ev_posix.h",
-    "src/core/lib/iomgr/exec_ctx.h",
-    "src/core/lib/iomgr/executor.h",
-    "src/core/lib/iomgr/iocp_windows.h",
-    "src/core/lib/iomgr/iomgr.h",
-    "src/core/lib/iomgr/iomgr_internal.h",
-    "src/core/lib/iomgr/iomgr_posix.h",
-    "src/core/lib/iomgr/load_file.h",
-    "src/core/lib/iomgr/network_status_tracker.h",
-    "src/core/lib/iomgr/polling_entity.h",
-    "src/core/lib/iomgr/pollset.h",
-    "src/core/lib/iomgr/pollset_set.h",
-    "src/core/lib/iomgr/pollset_set_windows.h",
-    "src/core/lib/iomgr/pollset_uv.h",
-    "src/core/lib/iomgr/pollset_windows.h",
-    "src/core/lib/iomgr/port.h",
-    "src/core/lib/iomgr/resolve_address.h",
-    "src/core/lib/iomgr/resource_quota.h",
-    "src/core/lib/iomgr/sockaddr.h",
-    "src/core/lib/iomgr/sockaddr_posix.h",
-    "src/core/lib/iomgr/sockaddr_utils.h",
-    "src/core/lib/iomgr/sockaddr_windows.h",
-    "src/core/lib/iomgr/socket_mutator.h",
-    "src/core/lib/iomgr/socket_utils.h",
-    "src/core/lib/iomgr/socket_utils_posix.h",
-    "src/core/lib/iomgr/socket_windows.h",
-    "src/core/lib/iomgr/tcp_client.h",
-    "src/core/lib/iomgr/tcp_client_posix.h",
-    "src/core/lib/iomgr/tcp_posix.h",
-    "src/core/lib/iomgr/tcp_server.h",
-    "src/core/lib/iomgr/tcp_uv.h",
-    "src/core/lib/iomgr/tcp_windows.h",
-    "src/core/lib/iomgr/time_averaged_stats.h",
-    "src/core/lib/iomgr/timer.h",
-    "src/core/lib/iomgr/timer_generic.h",
-    "src/core/lib/iomgr/timer_heap.h",
-    "src/core/lib/iomgr/timer_uv.h",
-    "src/core/lib/iomgr/udp_server.h",
-    "src/core/lib/iomgr/unix_sockets_posix.h",
-    "src/core/lib/iomgr/wakeup_fd_cv.h",
-    "src/core/lib/iomgr/wakeup_fd_pipe.h",
-    "src/core/lib/iomgr/wakeup_fd_posix.h",
-    "src/core/lib/iomgr/workqueue.h",
-    "src/core/lib/iomgr/workqueue_uv.h",
-    "src/core/lib/iomgr/workqueue_windows.h",
-    "src/core/lib/json/json.h",
-    "src/core/lib/json/json_common.h",
-    "src/core/lib/json/json_reader.h",
-    "src/core/lib/json/json_writer.h",
-    "src/core/lib/slice/percent_encoding.h",
-    "src/core/lib/slice/slice_string_helpers.h",
-    "src/core/lib/surface/api_trace.h",
-    "src/core/lib/surface/call.h",
-    "src/core/lib/surface/call_test_only.h",
-    "src/core/lib/surface/channel.h",
-    "src/core/lib/surface/channel_init.h",
-    "src/core/lib/surface/channel_stack_type.h",
-    "src/core/lib/surface/completion_queue.h",
-    "src/core/lib/surface/event_string.h",
-    "src/core/lib/surface/init.h",
-    "src/core/lib/surface/lame_client.h",
-    "src/core/lib/surface/server.h",
-    "src/core/lib/transport/byte_stream.h",
-    "src/core/lib/transport/connectivity_state.h",
-    "src/core/lib/transport/mdstr_hash_table.h",
-    "src/core/lib/transport/metadata.h",
-    "src/core/lib/transport/metadata_batch.h",
-    "src/core/lib/transport/pid_controller.h",
-    "src/core/lib/transport/service_config.h",
-    "src/core/lib/transport/static_metadata.h",
-    "src/core/lib/transport/timeout_encoding.h",
-    "src/core/lib/transport/transport.h",
-    "src/core/lib/transport/transport_impl.h",
-    "third_party/objective_c/Cronet/cronet_c_for_grpc.h",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.h",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
-    "src/core/ext/transport/chttp2/transport/frame.h",
-    "src/core/ext/transport/chttp2/transport/frame_data.h",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
-    "src/core/ext/transport/chttp2/transport/frame_ping.h",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
-    "src/core/ext/transport/chttp2/transport/frame_settings.h",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
-    "src/core/ext/transport/chttp2/transport/hpack_table.h",
-    "src/core/ext/transport/chttp2/transport/http2_errors.h",
-    "src/core/ext/transport/chttp2/transport/huffsyms.h",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
-    "src/core/ext/transport/chttp2/transport/internal.h",
-    "src/core/ext/transport/chttp2/transport/status_conversion.h",
-    "src/core/ext/transport/chttp2/transport/stream_map.h",
-    "src/core/ext/transport/chttp2/transport/varint.h",
-    "src/core/ext/transport/chttp2/alpn/alpn.h",
-    "src/core/ext/client_channel/client_channel.h",
-    "src/core/ext/client_channel/client_channel_factory.h",
-    "src/core/ext/client_channel/connector.h",
-    "src/core/ext/client_channel/http_connect_handshaker.h",
-    "src/core/ext/client_channel/initial_connect_string.h",
-    "src/core/ext/client_channel/lb_policy.h",
-    "src/core/ext/client_channel/lb_policy_factory.h",
-    "src/core/ext/client_channel/lb_policy_registry.h",
-    "src/core/ext/client_channel/parse_address.h",
-    "src/core/ext/client_channel/resolver.h",
-    "src/core/ext/client_channel/resolver_factory.h",
-    "src/core/ext/client_channel/resolver_registry.h",
-    "src/core/ext/client_channel/subchannel.h",
-    "src/core/ext/client_channel/subchannel_index.h",
-    "src/core/ext/client_channel/uri_parser.h",
-    "src/core/lib/security/context/security_context.h",
-    "src/core/lib/security/credentials/composite/composite_credentials.h",
-    "src/core/lib/security/credentials/credentials.h",
-    "src/core/lib/security/credentials/fake/fake_credentials.h",
-    "src/core/lib/security/credentials/google_default/google_default_credentials.h",
-    "src/core/lib/security/credentials/iam/iam_credentials.h",
-    "src/core/lib/security/credentials/jwt/json_token.h",
-    "src/core/lib/security/credentials/jwt/jwt_credentials.h",
-    "src/core/lib/security/credentials/jwt/jwt_verifier.h",
-    "src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
-    "src/core/lib/security/credentials/plugin/plugin_credentials.h",
-    "src/core/lib/security/credentials/ssl/ssl_credentials.h",
-    "src/core/lib/security/transport/auth_filters.h",
-    "src/core/lib/security/transport/secure_endpoint.h",
-    "src/core/lib/security/transport/security_connector.h",
-    "src/core/lib/security/transport/security_handshaker.h",
-    "src/core/lib/security/transport/tsi_error.h",
-    "src/core/lib/security/util/b64.h",
-    "src/core/lib/security/util/json_util.h",
-    "src/core/lib/tsi/fake_transport_security.h",
-    "src/core/lib/tsi/ssl_transport_security.h",
-    "src/core/lib/tsi/ssl_types.h",
-    "src/core/lib/tsi/transport_security.h",
-    "src/core/lib/tsi/transport_security_interface.h",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.h",
-    "src/core/lib/surface/init.c",
-    "src/core/lib/channel/channel_args.c",
-    "src/core/lib/channel/channel_stack.c",
-    "src/core/lib/channel/channel_stack_builder.c",
-    "src/core/lib/channel/compress_filter.c",
-    "src/core/lib/channel/connected_channel.c",
-    "src/core/lib/channel/deadline_filter.c",
-    "src/core/lib/channel/handshaker.c",
-    "src/core/lib/channel/http_client_filter.c",
-    "src/core/lib/channel/http_server_filter.c",
-    "src/core/lib/channel/message_size_filter.c",
-    "src/core/lib/compression/compression.c",
-    "src/core/lib/compression/message_compress.c",
-    "src/core/lib/debug/trace.c",
-    "src/core/lib/http/format_request.c",
-    "src/core/lib/http/httpcli.c",
-    "src/core/lib/http/parser.c",
-    "src/core/lib/iomgr/closure.c",
-    "src/core/lib/iomgr/combiner.c",
-    "src/core/lib/iomgr/endpoint.c",
-    "src/core/lib/iomgr/endpoint_pair_posix.c",
-    "src/core/lib/iomgr/endpoint_pair_uv.c",
-    "src/core/lib/iomgr/endpoint_pair_windows.c",
-    "src/core/lib/iomgr/error.c",
-    "src/core/lib/iomgr/ev_epoll_linux.c",
-    "src/core/lib/iomgr/ev_poll_posix.c",
-    "src/core/lib/iomgr/ev_posix.c",
-    "src/core/lib/iomgr/exec_ctx.c",
-    "src/core/lib/iomgr/executor.c",
-    "src/core/lib/iomgr/iocp_windows.c",
-    "src/core/lib/iomgr/iomgr.c",
-    "src/core/lib/iomgr/iomgr_posix.c",
-    "src/core/lib/iomgr/iomgr_uv.c",
-    "src/core/lib/iomgr/iomgr_windows.c",
-    "src/core/lib/iomgr/load_file.c",
-    "src/core/lib/iomgr/network_status_tracker.c",
-    "src/core/lib/iomgr/polling_entity.c",
-    "src/core/lib/iomgr/pollset_set_uv.c",
-    "src/core/lib/iomgr/pollset_set_windows.c",
-    "src/core/lib/iomgr/pollset_uv.c",
-    "src/core/lib/iomgr/pollset_windows.c",
-    "src/core/lib/iomgr/resolve_address_posix.c",
-    "src/core/lib/iomgr/resolve_address_uv.c",
-    "src/core/lib/iomgr/resolve_address_windows.c",
-    "src/core/lib/iomgr/resource_quota.c",
-    "src/core/lib/iomgr/sockaddr_utils.c",
-    "src/core/lib/iomgr/socket_mutator.c",
-    "src/core/lib/iomgr/socket_utils_common_posix.c",
-    "src/core/lib/iomgr/socket_utils_linux.c",
-    "src/core/lib/iomgr/socket_utils_posix.c",
-    "src/core/lib/iomgr/socket_utils_uv.c",
-    "src/core/lib/iomgr/socket_utils_windows.c",
-    "src/core/lib/iomgr/socket_windows.c",
-    "src/core/lib/iomgr/tcp_client_posix.c",
-    "src/core/lib/iomgr/tcp_client_uv.c",
-    "src/core/lib/iomgr/tcp_client_windows.c",
-    "src/core/lib/iomgr/tcp_posix.c",
-    "src/core/lib/iomgr/tcp_server_posix.c",
-    "src/core/lib/iomgr/tcp_server_uv.c",
-    "src/core/lib/iomgr/tcp_server_windows.c",
-    "src/core/lib/iomgr/tcp_uv.c",
-    "src/core/lib/iomgr/tcp_windows.c",
-    "src/core/lib/iomgr/time_averaged_stats.c",
-    "src/core/lib/iomgr/timer_generic.c",
-    "src/core/lib/iomgr/timer_heap.c",
-    "src/core/lib/iomgr/timer_uv.c",
-    "src/core/lib/iomgr/udp_server.c",
-    "src/core/lib/iomgr/unix_sockets_posix.c",
-    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
-    "src/core/lib/iomgr/wakeup_fd_cv.c",
-    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
-    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
-    "src/core/lib/iomgr/wakeup_fd_pipe.c",
-    "src/core/lib/iomgr/wakeup_fd_posix.c",
-    "src/core/lib/iomgr/workqueue_uv.c",
-    "src/core/lib/iomgr/workqueue_windows.c",
-    "src/core/lib/json/json.c",
-    "src/core/lib/json/json_reader.c",
-    "src/core/lib/json/json_string.c",
-    "src/core/lib/json/json_writer.c",
-    "src/core/lib/slice/percent_encoding.c",
-    "src/core/lib/slice/slice.c",
-    "src/core/lib/slice/slice_buffer.c",
-    "src/core/lib/slice/slice_string_helpers.c",
-    "src/core/lib/surface/alarm.c",
-    "src/core/lib/surface/api_trace.c",
-    "src/core/lib/surface/byte_buffer.c",
-    "src/core/lib/surface/byte_buffer_reader.c",
-    "src/core/lib/surface/call.c",
-    "src/core/lib/surface/call_details.c",
-    "src/core/lib/surface/call_log_batch.c",
-    "src/core/lib/surface/channel.c",
-    "src/core/lib/surface/channel_init.c",
-    "src/core/lib/surface/channel_ping.c",
-    "src/core/lib/surface/channel_stack_type.c",
-    "src/core/lib/surface/completion_queue.c",
-    "src/core/lib/surface/event_string.c",
-    "src/core/lib/surface/lame_client.c",
-    "src/core/lib/surface/metadata_array.c",
-    "src/core/lib/surface/server.c",
-    "src/core/lib/surface/validate_metadata.c",
-    "src/core/lib/surface/version.c",
-    "src/core/lib/transport/byte_stream.c",
-    "src/core/lib/transport/connectivity_state.c",
-    "src/core/lib/transport/mdstr_hash_table.c",
-    "src/core/lib/transport/metadata.c",
-    "src/core/lib/transport/metadata_batch.c",
-    "src/core/lib/transport/pid_controller.c",
-    "src/core/lib/transport/service_config.c",
-    "src/core/lib/transport/static_metadata.c",
-    "src/core/lib/transport/timeout_encoding.c",
-    "src/core/lib/transport/transport.c",
-    "src/core/lib/transport/transport_op_string.c",
-    "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c",
-    "src/core/ext/transport/cronet/transport/cronet_api_dummy.c",
-    "src/core/ext/transport/cronet/transport/cronet_transport.c",
-    "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.c",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
-    "src/core/ext/transport/chttp2/transport/frame_data.c",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
-    "src/core/ext/transport/chttp2/transport/frame_ping.c",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
-    "src/core/ext/transport/chttp2/transport/frame_settings.c",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
-    "src/core/ext/transport/chttp2/transport/hpack_table.c",
-    "src/core/ext/transport/chttp2/transport/huffsyms.c",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
-    "src/core/ext/transport/chttp2/transport/parsing.c",
-    "src/core/ext/transport/chttp2/transport/status_conversion.c",
-    "src/core/ext/transport/chttp2/transport/stream_lists.c",
-    "src/core/ext/transport/chttp2/transport/stream_map.c",
-    "src/core/ext/transport/chttp2/transport/varint.c",
-    "src/core/ext/transport/chttp2/transport/writing.c",
-    "src/core/ext/transport/chttp2/alpn/alpn.c",
-    "src/core/ext/client_channel/channel_connectivity.c",
-    "src/core/ext/client_channel/client_channel.c",
-    "src/core/ext/client_channel/client_channel_factory.c",
-    "src/core/ext/client_channel/client_channel_plugin.c",
-    "src/core/ext/client_channel/connector.c",
-    "src/core/ext/client_channel/default_initial_connect_string.c",
-    "src/core/ext/client_channel/http_connect_handshaker.c",
-    "src/core/ext/client_channel/initial_connect_string.c",
-    "src/core/ext/client_channel/lb_policy.c",
-    "src/core/ext/client_channel/lb_policy_factory.c",
-    "src/core/ext/client_channel/lb_policy_registry.c",
-    "src/core/ext/client_channel/parse_address.c",
-    "src/core/ext/client_channel/resolver.c",
-    "src/core/ext/client_channel/resolver_factory.c",
-    "src/core/ext/client_channel/resolver_registry.c",
-    "src/core/ext/client_channel/subchannel.c",
-    "src/core/ext/client_channel/subchannel_index.c",
-    "src/core/ext/client_channel/uri_parser.c",
-    "src/core/lib/http/httpcli_security_connector.c",
-    "src/core/lib/security/context/security_context.c",
-    "src/core/lib/security/credentials/composite/composite_credentials.c",
-    "src/core/lib/security/credentials/credentials.c",
-    "src/core/lib/security/credentials/credentials_metadata.c",
-    "src/core/lib/security/credentials/fake/fake_credentials.c",
-    "src/core/lib/security/credentials/google_default/credentials_generic.c",
-    "src/core/lib/security/credentials/google_default/google_default_credentials.c",
-    "src/core/lib/security/credentials/iam/iam_credentials.c",
-    "src/core/lib/security/credentials/jwt/json_token.c",
-    "src/core/lib/security/credentials/jwt/jwt_credentials.c",
-    "src/core/lib/security/credentials/jwt/jwt_verifier.c",
-    "src/core/lib/security/credentials/oauth2/oauth2_credentials.c",
-    "src/core/lib/security/credentials/plugin/plugin_credentials.c",
-    "src/core/lib/security/credentials/ssl/ssl_credentials.c",
-    "src/core/lib/security/transport/client_auth_filter.c",
-    "src/core/lib/security/transport/secure_endpoint.c",
-    "src/core/lib/security/transport/security_connector.c",
-    "src/core/lib/security/transport/security_handshaker.c",
-    "src/core/lib/security/transport/server_auth_filter.c",
-    "src/core/lib/security/transport/tsi_error.c",
-    "src/core/lib/security/util/b64.c",
-    "src/core/lib/security/util/json_util.c",
-    "src/core/lib/surface/init_secure.c",
-    "src/core/lib/tsi/fake_transport_security.c",
-    "src/core/lib/tsi/ssl_transport_security.c",
-    "src/core/lib/tsi/transport_security.c",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.c",
-    "src/core/plugin_registry/grpc_cronet_plugin_registry.c",
-  ],
-  hdrs = [
-    "include/grpc/byte_buffer.h",
-    "include/grpc/byte_buffer_reader.h",
-    "include/grpc/compression.h",
-    "include/grpc/grpc.h",
-    "include/grpc/grpc_posix.h",
-    "include/grpc/grpc_security_constants.h",
-    "include/grpc/slice.h",
-    "include/grpc/slice_buffer.h",
-    "include/grpc/status.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/grpc_cronet.h",
-    "include/grpc/grpc_security.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    "//external:libssl",
-    ":gpr",
-  ],
+grpc_cc_library(
+    name = "grpc_transport_chttp2_client_insecure",
+    srcs = [
+        "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
+        "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+        "grpc_transport_chttp2",
+        "grpc_transport_chttp2_client_connector",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc_unsecure",
-  srcs = [
-    "src/core/lib/channel/channel_args.h",
-    "src/core/lib/channel/channel_stack.h",
-    "src/core/lib/channel/channel_stack_builder.h",
-    "src/core/lib/channel/compress_filter.h",
-    "src/core/lib/channel/connected_channel.h",
-    "src/core/lib/channel/context.h",
-    "src/core/lib/channel/deadline_filter.h",
-    "src/core/lib/channel/handshaker.h",
-    "src/core/lib/channel/http_client_filter.h",
-    "src/core/lib/channel/http_server_filter.h",
-    "src/core/lib/channel/message_size_filter.h",
-    "src/core/lib/compression/algorithm_metadata.h",
-    "src/core/lib/compression/message_compress.h",
-    "src/core/lib/debug/trace.h",
-    "src/core/lib/http/format_request.h",
-    "src/core/lib/http/httpcli.h",
-    "src/core/lib/http/parser.h",
-    "src/core/lib/iomgr/closure.h",
-    "src/core/lib/iomgr/combiner.h",
-    "src/core/lib/iomgr/endpoint.h",
-    "src/core/lib/iomgr/endpoint_pair.h",
-    "src/core/lib/iomgr/error.h",
-    "src/core/lib/iomgr/ev_epoll_linux.h",
-    "src/core/lib/iomgr/ev_poll_posix.h",
-    "src/core/lib/iomgr/ev_posix.h",
-    "src/core/lib/iomgr/exec_ctx.h",
-    "src/core/lib/iomgr/executor.h",
-    "src/core/lib/iomgr/iocp_windows.h",
-    "src/core/lib/iomgr/iomgr.h",
-    "src/core/lib/iomgr/iomgr_internal.h",
-    "src/core/lib/iomgr/iomgr_posix.h",
-    "src/core/lib/iomgr/load_file.h",
-    "src/core/lib/iomgr/network_status_tracker.h",
-    "src/core/lib/iomgr/polling_entity.h",
-    "src/core/lib/iomgr/pollset.h",
-    "src/core/lib/iomgr/pollset_set.h",
-    "src/core/lib/iomgr/pollset_set_windows.h",
-    "src/core/lib/iomgr/pollset_uv.h",
-    "src/core/lib/iomgr/pollset_windows.h",
-    "src/core/lib/iomgr/port.h",
-    "src/core/lib/iomgr/resolve_address.h",
-    "src/core/lib/iomgr/resource_quota.h",
-    "src/core/lib/iomgr/sockaddr.h",
-    "src/core/lib/iomgr/sockaddr_posix.h",
-    "src/core/lib/iomgr/sockaddr_utils.h",
-    "src/core/lib/iomgr/sockaddr_windows.h",
-    "src/core/lib/iomgr/socket_mutator.h",
-    "src/core/lib/iomgr/socket_utils.h",
-    "src/core/lib/iomgr/socket_utils_posix.h",
-    "src/core/lib/iomgr/socket_windows.h",
-    "src/core/lib/iomgr/tcp_client.h",
-    "src/core/lib/iomgr/tcp_client_posix.h",
-    "src/core/lib/iomgr/tcp_posix.h",
-    "src/core/lib/iomgr/tcp_server.h",
-    "src/core/lib/iomgr/tcp_uv.h",
-    "src/core/lib/iomgr/tcp_windows.h",
-    "src/core/lib/iomgr/time_averaged_stats.h",
-    "src/core/lib/iomgr/timer.h",
-    "src/core/lib/iomgr/timer_generic.h",
-    "src/core/lib/iomgr/timer_heap.h",
-    "src/core/lib/iomgr/timer_uv.h",
-    "src/core/lib/iomgr/udp_server.h",
-    "src/core/lib/iomgr/unix_sockets_posix.h",
-    "src/core/lib/iomgr/wakeup_fd_cv.h",
-    "src/core/lib/iomgr/wakeup_fd_pipe.h",
-    "src/core/lib/iomgr/wakeup_fd_posix.h",
-    "src/core/lib/iomgr/workqueue.h",
-    "src/core/lib/iomgr/workqueue_uv.h",
-    "src/core/lib/iomgr/workqueue_windows.h",
-    "src/core/lib/json/json.h",
-    "src/core/lib/json/json_common.h",
-    "src/core/lib/json/json_reader.h",
-    "src/core/lib/json/json_writer.h",
-    "src/core/lib/slice/percent_encoding.h",
-    "src/core/lib/slice/slice_string_helpers.h",
-    "src/core/lib/surface/api_trace.h",
-    "src/core/lib/surface/call.h",
-    "src/core/lib/surface/call_test_only.h",
-    "src/core/lib/surface/channel.h",
-    "src/core/lib/surface/channel_init.h",
-    "src/core/lib/surface/channel_stack_type.h",
-    "src/core/lib/surface/completion_queue.h",
-    "src/core/lib/surface/event_string.h",
-    "src/core/lib/surface/init.h",
-    "src/core/lib/surface/lame_client.h",
-    "src/core/lib/surface/server.h",
-    "src/core/lib/transport/byte_stream.h",
-    "src/core/lib/transport/connectivity_state.h",
-    "src/core/lib/transport/mdstr_hash_table.h",
-    "src/core/lib/transport/metadata.h",
-    "src/core/lib/transport/metadata_batch.h",
-    "src/core/lib/transport/pid_controller.h",
-    "src/core/lib/transport/service_config.h",
-    "src/core/lib/transport/static_metadata.h",
-    "src/core/lib/transport/timeout_encoding.h",
-    "src/core/lib/transport/transport.h",
-    "src/core/lib/transport/transport_impl.h",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.h",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
-    "src/core/ext/transport/chttp2/transport/frame.h",
-    "src/core/ext/transport/chttp2/transport/frame_data.h",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
-    "src/core/ext/transport/chttp2/transport/frame_ping.h",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
-    "src/core/ext/transport/chttp2/transport/frame_settings.h",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
-    "src/core/ext/transport/chttp2/transport/hpack_table.h",
-    "src/core/ext/transport/chttp2/transport/http2_errors.h",
-    "src/core/ext/transport/chttp2/transport/huffsyms.h",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
-    "src/core/ext/transport/chttp2/transport/internal.h",
-    "src/core/ext/transport/chttp2/transport/status_conversion.h",
-    "src/core/ext/transport/chttp2/transport/stream_map.h",
-    "src/core/ext/transport/chttp2/transport/varint.h",
-    "src/core/ext/transport/chttp2/alpn/alpn.h",
-    "src/core/ext/transport/chttp2/server/chttp2_server.h",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.h",
-    "src/core/ext/client_channel/client_channel.h",
-    "src/core/ext/client_channel/client_channel_factory.h",
-    "src/core/ext/client_channel/connector.h",
-    "src/core/ext/client_channel/http_connect_handshaker.h",
-    "src/core/ext/client_channel/initial_connect_string.h",
-    "src/core/ext/client_channel/lb_policy.h",
-    "src/core/ext/client_channel/lb_policy_factory.h",
-    "src/core/ext/client_channel/lb_policy_registry.h",
-    "src/core/ext/client_channel/parse_address.h",
-    "src/core/ext/client_channel/resolver.h",
-    "src/core/ext/client_channel/resolver_factory.h",
-    "src/core/ext/client_channel/resolver_registry.h",
-    "src/core/ext/client_channel/subchannel.h",
-    "src/core/ext/client_channel/subchannel_index.h",
-    "src/core/ext/client_channel/uri_parser.h",
-    "src/core/ext/load_reporting/load_reporting.h",
-    "src/core/ext/load_reporting/load_reporting_filter.h",
-    "src/core/ext/lb_policy/grpclb/grpclb.h",
-    "src/core/ext/lb_policy/grpclb/load_balancer_api.h",
-    "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
-    "src/core/ext/census/aggregation.h",
-    "src/core/ext/census/base_resources.h",
-    "src/core/ext/census/census_interface.h",
-    "src/core/ext/census/census_rpc_stats.h",
-    "src/core/ext/census/gen/census.pb.h",
-    "src/core/ext/census/gen/trace_context.pb.h",
-    "src/core/ext/census/grpc_filter.h",
-    "src/core/ext/census/mlog.h",
-    "src/core/ext/census/resource.h",
-    "src/core/ext/census/rpc_metric_id.h",
-    "src/core/ext/census/trace_context.h",
-    "src/core/lib/surface/init.c",
-    "src/core/lib/surface/init_unsecure.c",
-    "src/core/lib/channel/channel_args.c",
-    "src/core/lib/channel/channel_stack.c",
-    "src/core/lib/channel/channel_stack_builder.c",
-    "src/core/lib/channel/compress_filter.c",
-    "src/core/lib/channel/connected_channel.c",
-    "src/core/lib/channel/deadline_filter.c",
-    "src/core/lib/channel/handshaker.c",
-    "src/core/lib/channel/http_client_filter.c",
-    "src/core/lib/channel/http_server_filter.c",
-    "src/core/lib/channel/message_size_filter.c",
-    "src/core/lib/compression/compression.c",
-    "src/core/lib/compression/message_compress.c",
-    "src/core/lib/debug/trace.c",
-    "src/core/lib/http/format_request.c",
-    "src/core/lib/http/httpcli.c",
-    "src/core/lib/http/parser.c",
-    "src/core/lib/iomgr/closure.c",
-    "src/core/lib/iomgr/combiner.c",
-    "src/core/lib/iomgr/endpoint.c",
-    "src/core/lib/iomgr/endpoint_pair_posix.c",
-    "src/core/lib/iomgr/endpoint_pair_uv.c",
-    "src/core/lib/iomgr/endpoint_pair_windows.c",
-    "src/core/lib/iomgr/error.c",
-    "src/core/lib/iomgr/ev_epoll_linux.c",
-    "src/core/lib/iomgr/ev_poll_posix.c",
-    "src/core/lib/iomgr/ev_posix.c",
-    "src/core/lib/iomgr/exec_ctx.c",
-    "src/core/lib/iomgr/executor.c",
-    "src/core/lib/iomgr/iocp_windows.c",
-    "src/core/lib/iomgr/iomgr.c",
-    "src/core/lib/iomgr/iomgr_posix.c",
-    "src/core/lib/iomgr/iomgr_uv.c",
-    "src/core/lib/iomgr/iomgr_windows.c",
-    "src/core/lib/iomgr/load_file.c",
-    "src/core/lib/iomgr/network_status_tracker.c",
-    "src/core/lib/iomgr/polling_entity.c",
-    "src/core/lib/iomgr/pollset_set_uv.c",
-    "src/core/lib/iomgr/pollset_set_windows.c",
-    "src/core/lib/iomgr/pollset_uv.c",
-    "src/core/lib/iomgr/pollset_windows.c",
-    "src/core/lib/iomgr/resolve_address_posix.c",
-    "src/core/lib/iomgr/resolve_address_uv.c",
-    "src/core/lib/iomgr/resolve_address_windows.c",
-    "src/core/lib/iomgr/resource_quota.c",
-    "src/core/lib/iomgr/sockaddr_utils.c",
-    "src/core/lib/iomgr/socket_mutator.c",
-    "src/core/lib/iomgr/socket_utils_common_posix.c",
-    "src/core/lib/iomgr/socket_utils_linux.c",
-    "src/core/lib/iomgr/socket_utils_posix.c",
-    "src/core/lib/iomgr/socket_utils_uv.c",
-    "src/core/lib/iomgr/socket_utils_windows.c",
-    "src/core/lib/iomgr/socket_windows.c",
-    "src/core/lib/iomgr/tcp_client_posix.c",
-    "src/core/lib/iomgr/tcp_client_uv.c",
-    "src/core/lib/iomgr/tcp_client_windows.c",
-    "src/core/lib/iomgr/tcp_posix.c",
-    "src/core/lib/iomgr/tcp_server_posix.c",
-    "src/core/lib/iomgr/tcp_server_uv.c",
-    "src/core/lib/iomgr/tcp_server_windows.c",
-    "src/core/lib/iomgr/tcp_uv.c",
-    "src/core/lib/iomgr/tcp_windows.c",
-    "src/core/lib/iomgr/time_averaged_stats.c",
-    "src/core/lib/iomgr/timer_generic.c",
-    "src/core/lib/iomgr/timer_heap.c",
-    "src/core/lib/iomgr/timer_uv.c",
-    "src/core/lib/iomgr/udp_server.c",
-    "src/core/lib/iomgr/unix_sockets_posix.c",
-    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
-    "src/core/lib/iomgr/wakeup_fd_cv.c",
-    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
-    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
-    "src/core/lib/iomgr/wakeup_fd_pipe.c",
-    "src/core/lib/iomgr/wakeup_fd_posix.c",
-    "src/core/lib/iomgr/workqueue_uv.c",
-    "src/core/lib/iomgr/workqueue_windows.c",
-    "src/core/lib/json/json.c",
-    "src/core/lib/json/json_reader.c",
-    "src/core/lib/json/json_string.c",
-    "src/core/lib/json/json_writer.c",
-    "src/core/lib/slice/percent_encoding.c",
-    "src/core/lib/slice/slice.c",
-    "src/core/lib/slice/slice_buffer.c",
-    "src/core/lib/slice/slice_string_helpers.c",
-    "src/core/lib/surface/alarm.c",
-    "src/core/lib/surface/api_trace.c",
-    "src/core/lib/surface/byte_buffer.c",
-    "src/core/lib/surface/byte_buffer_reader.c",
-    "src/core/lib/surface/call.c",
-    "src/core/lib/surface/call_details.c",
-    "src/core/lib/surface/call_log_batch.c",
-    "src/core/lib/surface/channel.c",
-    "src/core/lib/surface/channel_init.c",
-    "src/core/lib/surface/channel_ping.c",
-    "src/core/lib/surface/channel_stack_type.c",
-    "src/core/lib/surface/completion_queue.c",
-    "src/core/lib/surface/event_string.c",
-    "src/core/lib/surface/lame_client.c",
-    "src/core/lib/surface/metadata_array.c",
-    "src/core/lib/surface/server.c",
-    "src/core/lib/surface/validate_metadata.c",
-    "src/core/lib/surface/version.c",
-    "src/core/lib/transport/byte_stream.c",
-    "src/core/lib/transport/connectivity_state.c",
-    "src/core/lib/transport/mdstr_hash_table.c",
-    "src/core/lib/transport/metadata.c",
-    "src/core/lib/transport/metadata_batch.c",
-    "src/core/lib/transport/pid_controller.c",
-    "src/core/lib/transport/service_config.c",
-    "src/core/lib/transport/static_metadata.c",
-    "src/core/lib/transport/timeout_encoding.c",
-    "src/core/lib/transport/transport.c",
-    "src/core/lib/transport/transport_op_string.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.c",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
-    "src/core/ext/transport/chttp2/transport/frame_data.c",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
-    "src/core/ext/transport/chttp2/transport/frame_ping.c",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
-    "src/core/ext/transport/chttp2/transport/frame_settings.c",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
-    "src/core/ext/transport/chttp2/transport/hpack_table.c",
-    "src/core/ext/transport/chttp2/transport/huffsyms.c",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
-    "src/core/ext/transport/chttp2/transport/parsing.c",
-    "src/core/ext/transport/chttp2/transport/status_conversion.c",
-    "src/core/ext/transport/chttp2/transport/stream_lists.c",
-    "src/core/ext/transport/chttp2/transport/stream_map.c",
-    "src/core/ext/transport/chttp2/transport/varint.c",
-    "src/core/ext/transport/chttp2/transport/writing.c",
-    "src/core/ext/transport/chttp2/alpn/alpn.c",
-    "src/core/ext/transport/chttp2/server/chttp2_server.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.c",
-    "src/core/ext/client_channel/channel_connectivity.c",
-    "src/core/ext/client_channel/client_channel.c",
-    "src/core/ext/client_channel/client_channel_factory.c",
-    "src/core/ext/client_channel/client_channel_plugin.c",
-    "src/core/ext/client_channel/connector.c",
-    "src/core/ext/client_channel/default_initial_connect_string.c",
-    "src/core/ext/client_channel/http_connect_handshaker.c",
-    "src/core/ext/client_channel/initial_connect_string.c",
-    "src/core/ext/client_channel/lb_policy.c",
-    "src/core/ext/client_channel/lb_policy_factory.c",
-    "src/core/ext/client_channel/lb_policy_registry.c",
-    "src/core/ext/client_channel/parse_address.c",
-    "src/core/ext/client_channel/resolver.c",
-    "src/core/ext/client_channel/resolver_factory.c",
-    "src/core/ext/client_channel/resolver_registry.c",
-    "src/core/ext/client_channel/subchannel.c",
-    "src/core/ext/client_channel/subchannel_index.c",
-    "src/core/ext/client_channel/uri_parser.c",
-    "src/core/ext/resolver/dns/native/dns_resolver.c",
-    "src/core/ext/resolver/sockaddr/sockaddr_resolver.c",
-    "src/core/ext/load_reporting/load_reporting.c",
-    "src/core/ext/load_reporting/load_reporting_filter.c",
-    "src/core/ext/lb_policy/grpclb/grpclb.c",
-    "src/core/ext/lb_policy/grpclb/load_balancer_api.c",
-    "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
-    "src/core/ext/lb_policy/pick_first/pick_first.c",
-    "src/core/ext/lb_policy/round_robin/round_robin.c",
-    "src/core/ext/census/base_resources.c",
-    "src/core/ext/census/context.c",
-    "src/core/ext/census/gen/census.pb.c",
-    "src/core/ext/census/gen/trace_context.pb.c",
-    "src/core/ext/census/grpc_context.c",
-    "src/core/ext/census/grpc_filter.c",
-    "src/core/ext/census/grpc_plugin.c",
-    "src/core/ext/census/initialize.c",
-    "src/core/ext/census/mlog.c",
-    "src/core/ext/census/operation.c",
-    "src/core/ext/census/placeholders.c",
-    "src/core/ext/census/resource.c",
-    "src/core/ext/census/trace_context.c",
-    "src/core/ext/census/tracing.c",
-    "src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
-  ],
-  hdrs = [
-    "include/grpc/byte_buffer.h",
-    "include/grpc/byte_buffer_reader.h",
-    "include/grpc/compression.h",
-    "include/grpc/grpc.h",
-    "include/grpc/grpc_posix.h",
-    "include/grpc/grpc_security_constants.h",
-    "include/grpc/slice.h",
-    "include/grpc/slice_buffer.h",
-    "include/grpc/status.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/census.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    ":gpr",
-    "//external:nanopb",
-  ],
-  copts = [
-    "-std=gnu99",
-  ],
+grpc_cc_library(
+    name = "grpc_transport_chttp2_client_secure",
+    srcs = [
+        "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_client_channel",
+        "grpc_secure",
+        "grpc_transport_chttp2",
+        "grpc_transport_chttp2_client_connector",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc++",
-  srcs = [
-    "include/grpc++/impl/codegen/core_codegen.h",
-    "src/cpp/client/secure_credentials.h",
-    "src/cpp/common/secure_auth_context.h",
-    "src/cpp/server/secure_server_credentials.h",
-    "src/cpp/client/create_channel_internal.h",
-    "src/cpp/common/channel_filter.h",
-    "src/cpp/server/dynamic_thread_pool.h",
-    "src/cpp/server/thread_pool_interface.h",
-    "src/cpp/thread_manager/thread_manager.h",
-    "src/cpp/client/insecure_credentials.cc",
-    "src/cpp/client/secure_credentials.cc",
-    "src/cpp/common/auth_property_iterator.cc",
-    "src/cpp/common/secure_auth_context.cc",
-    "src/cpp/common/secure_channel_arguments.cc",
-    "src/cpp/common/secure_create_auth_context.cc",
-    "src/cpp/server/insecure_server_credentials.cc",
-    "src/cpp/server/secure_server_credentials.cc",
-    "src/cpp/client/channel_cc.cc",
-    "src/cpp/client/client_context.cc",
-    "src/cpp/client/create_channel.cc",
-    "src/cpp/client/create_channel_internal.cc",
-    "src/cpp/client/create_channel_posix.cc",
-    "src/cpp/client/credentials_cc.cc",
-    "src/cpp/client/generic_stub.cc",
-    "src/cpp/common/channel_arguments.cc",
-    "src/cpp/common/channel_filter.cc",
-    "src/cpp/common/completion_queue_cc.cc",
-    "src/cpp/common/core_codegen.cc",
-    "src/cpp/common/resource_quota_cc.cc",
-    "src/cpp/common/rpc_method.cc",
-    "src/cpp/common/version_cc.cc",
-    "src/cpp/server/async_generic_service.cc",
-    "src/cpp/server/create_default_thread_pool.cc",
-    "src/cpp/server/dynamic_thread_pool.cc",
-    "src/cpp/server/server_builder.cc",
-    "src/cpp/server/server_cc.cc",
-    "src/cpp/server/server_context.cc",
-    "src/cpp/server/server_credentials.cc",
-    "src/cpp/server/server_posix.cc",
-    "src/cpp/thread_manager/thread_manager.cc",
-    "src/cpp/util/byte_buffer_cc.cc",
-    "src/cpp/util/slice_cc.cc",
-    "src/cpp/util/status.cc",
-    "src/cpp/util/string_ref.cc",
-    "src/cpp/util/time_cc.cc",
-    "src/cpp/codegen/codegen_init.cc",
-  ],
-  hdrs = [
-    "include/grpc++/alarm.h",
-    "include/grpc++/channel.h",
-    "include/grpc++/client_context.h",
-    "include/grpc++/completion_queue.h",
-    "include/grpc++/create_channel.h",
-    "include/grpc++/create_channel_posix.h",
-    "include/grpc++/generic/async_generic_service.h",
-    "include/grpc++/generic/generic_stub.h",
-    "include/grpc++/grpc++.h",
-    "include/grpc++/impl/call.h",
-    "include/grpc++/impl/client_unary_call.h",
-    "include/grpc++/impl/codegen/core_codegen.h",
-    "include/grpc++/impl/grpc_library.h",
-    "include/grpc++/impl/method_handler_impl.h",
-    "include/grpc++/impl/rpc_method.h",
-    "include/grpc++/impl/rpc_service_method.h",
-    "include/grpc++/impl/serialization_traits.h",
-    "include/grpc++/impl/server_builder_option.h",
-    "include/grpc++/impl/server_builder_plugin.h",
-    "include/grpc++/impl/server_initializer.h",
-    "include/grpc++/impl/service_type.h",
-    "include/grpc++/resource_quota.h",
-    "include/grpc++/security/auth_context.h",
-    "include/grpc++/security/auth_metadata_processor.h",
-    "include/grpc++/security/credentials.h",
-    "include/grpc++/security/server_credentials.h",
-    "include/grpc++/server.h",
-    "include/grpc++/server_builder.h",
-    "include/grpc++/server_context.h",
-    "include/grpc++/server_posix.h",
-    "include/grpc++/support/async_stream.h",
-    "include/grpc++/support/async_unary_call.h",
-    "include/grpc++/support/byte_buffer.h",
-    "include/grpc++/support/channel_arguments.h",
-    "include/grpc++/support/config.h",
-    "include/grpc++/support/slice.h",
-    "include/grpc++/support/status.h",
-    "include/grpc++/support/status_code_enum.h",
-    "include/grpc++/support/string_ref.h",
-    "include/grpc++/support/stub_options.h",
-    "include/grpc++/support/sync_stream.h",
-    "include/grpc++/support/time.h",
-    "include/grpc++/impl/codegen/async_stream.h",
-    "include/grpc++/impl/codegen/async_unary_call.h",
-    "include/grpc++/impl/codegen/call.h",
-    "include/grpc++/impl/codegen/call_hook.h",
-    "include/grpc++/impl/codegen/channel_interface.h",
-    "include/grpc++/impl/codegen/client_context.h",
-    "include/grpc++/impl/codegen/client_unary_call.h",
-    "include/grpc++/impl/codegen/completion_queue.h",
-    "include/grpc++/impl/codegen/completion_queue_tag.h",
-    "include/grpc++/impl/codegen/config.h",
-    "include/grpc++/impl/codegen/core_codegen_interface.h",
-    "include/grpc++/impl/codegen/create_auth_context.h",
-    "include/grpc++/impl/codegen/grpc_library.h",
-    "include/grpc++/impl/codegen/method_handler_impl.h",
-    "include/grpc++/impl/codegen/rpc_method.h",
-    "include/grpc++/impl/codegen/rpc_service_method.h",
-    "include/grpc++/impl/codegen/security/auth_context.h",
-    "include/grpc++/impl/codegen/serialization_traits.h",
-    "include/grpc++/impl/codegen/server_context.h",
-    "include/grpc++/impl/codegen/server_interface.h",
-    "include/grpc++/impl/codegen/service_type.h",
-    "include/grpc++/impl/codegen/status.h",
-    "include/grpc++/impl/codegen/status_code_enum.h",
-    "include/grpc++/impl/codegen/status_helper.h",
-    "include/grpc++/impl/codegen/string_ref.h",
-    "include/grpc++/impl/codegen/stub_options.h",
-    "include/grpc++/impl/codegen/sync_stream.h",
-    "include/grpc++/impl/codegen/time.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    "//external:libssl",
-    "//external:protobuf_clib",
-    ":grpc",
-  ],
+grpc_cc_library(
+    name = "grpc_transport_chttp2_server",
+    srcs = [
+        "src/core/ext/transport/chttp2/server/chttp2_server.c",
+    ],
+    hdrs = [
+        "src/core/ext/transport/chttp2/server/chttp2_server.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_transport_chttp2",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc++_cronet",
-  srcs = [
-    "src/cpp/client/create_channel_internal.h",
-    "src/cpp/common/channel_filter.h",
-    "src/cpp/server/dynamic_thread_pool.h",
-    "src/cpp/server/thread_pool_interface.h",
-    "src/cpp/thread_manager/thread_manager.h",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.h",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.h",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
-    "src/core/ext/transport/chttp2/transport/frame.h",
-    "src/core/ext/transport/chttp2/transport/frame_data.h",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
-    "src/core/ext/transport/chttp2/transport/frame_ping.h",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
-    "src/core/ext/transport/chttp2/transport/frame_settings.h",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
-    "src/core/ext/transport/chttp2/transport/hpack_table.h",
-    "src/core/ext/transport/chttp2/transport/http2_errors.h",
-    "src/core/ext/transport/chttp2/transport/huffsyms.h",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
-    "src/core/ext/transport/chttp2/transport/internal.h",
-    "src/core/ext/transport/chttp2/transport/status_conversion.h",
-    "src/core/ext/transport/chttp2/transport/stream_map.h",
-    "src/core/ext/transport/chttp2/transport/varint.h",
-    "src/core/lib/channel/channel_args.h",
-    "src/core/lib/channel/channel_stack.h",
-    "src/core/lib/channel/channel_stack_builder.h",
-    "src/core/lib/channel/compress_filter.h",
-    "src/core/lib/channel/connected_channel.h",
-    "src/core/lib/channel/context.h",
-    "src/core/lib/channel/deadline_filter.h",
-    "src/core/lib/channel/handshaker.h",
-    "src/core/lib/channel/http_client_filter.h",
-    "src/core/lib/channel/http_server_filter.h",
-    "src/core/lib/channel/message_size_filter.h",
-    "src/core/lib/compression/algorithm_metadata.h",
-    "src/core/lib/compression/message_compress.h",
-    "src/core/lib/debug/trace.h",
-    "src/core/lib/http/format_request.h",
-    "src/core/lib/http/httpcli.h",
-    "src/core/lib/http/parser.h",
-    "src/core/lib/iomgr/closure.h",
-    "src/core/lib/iomgr/combiner.h",
-    "src/core/lib/iomgr/endpoint.h",
-    "src/core/lib/iomgr/endpoint_pair.h",
-    "src/core/lib/iomgr/error.h",
-    "src/core/lib/iomgr/ev_epoll_linux.h",
-    "src/core/lib/iomgr/ev_poll_posix.h",
-    "src/core/lib/iomgr/ev_posix.h",
-    "src/core/lib/iomgr/exec_ctx.h",
-    "src/core/lib/iomgr/executor.h",
-    "src/core/lib/iomgr/iocp_windows.h",
-    "src/core/lib/iomgr/iomgr.h",
-    "src/core/lib/iomgr/iomgr_internal.h",
-    "src/core/lib/iomgr/iomgr_posix.h",
-    "src/core/lib/iomgr/load_file.h",
-    "src/core/lib/iomgr/network_status_tracker.h",
-    "src/core/lib/iomgr/polling_entity.h",
-    "src/core/lib/iomgr/pollset.h",
-    "src/core/lib/iomgr/pollset_set.h",
-    "src/core/lib/iomgr/pollset_set_windows.h",
-    "src/core/lib/iomgr/pollset_uv.h",
-    "src/core/lib/iomgr/pollset_windows.h",
-    "src/core/lib/iomgr/port.h",
-    "src/core/lib/iomgr/resolve_address.h",
-    "src/core/lib/iomgr/resource_quota.h",
-    "src/core/lib/iomgr/sockaddr.h",
-    "src/core/lib/iomgr/sockaddr_posix.h",
-    "src/core/lib/iomgr/sockaddr_utils.h",
-    "src/core/lib/iomgr/sockaddr_windows.h",
-    "src/core/lib/iomgr/socket_mutator.h",
-    "src/core/lib/iomgr/socket_utils.h",
-    "src/core/lib/iomgr/socket_utils_posix.h",
-    "src/core/lib/iomgr/socket_windows.h",
-    "src/core/lib/iomgr/tcp_client.h",
-    "src/core/lib/iomgr/tcp_client_posix.h",
-    "src/core/lib/iomgr/tcp_posix.h",
-    "src/core/lib/iomgr/tcp_server.h",
-    "src/core/lib/iomgr/tcp_uv.h",
-    "src/core/lib/iomgr/tcp_windows.h",
-    "src/core/lib/iomgr/time_averaged_stats.h",
-    "src/core/lib/iomgr/timer.h",
-    "src/core/lib/iomgr/timer_generic.h",
-    "src/core/lib/iomgr/timer_heap.h",
-    "src/core/lib/iomgr/timer_uv.h",
-    "src/core/lib/iomgr/udp_server.h",
-    "src/core/lib/iomgr/unix_sockets_posix.h",
-    "src/core/lib/iomgr/wakeup_fd_cv.h",
-    "src/core/lib/iomgr/wakeup_fd_pipe.h",
-    "src/core/lib/iomgr/wakeup_fd_posix.h",
-    "src/core/lib/iomgr/workqueue.h",
-    "src/core/lib/iomgr/workqueue_uv.h",
-    "src/core/lib/iomgr/workqueue_windows.h",
-    "src/core/lib/json/json.h",
-    "src/core/lib/json/json_common.h",
-    "src/core/lib/json/json_reader.h",
-    "src/core/lib/json/json_writer.h",
-    "src/core/lib/slice/percent_encoding.h",
-    "src/core/lib/slice/slice_string_helpers.h",
-    "src/core/lib/surface/api_trace.h",
-    "src/core/lib/surface/call.h",
-    "src/core/lib/surface/call_test_only.h",
-    "src/core/lib/surface/channel.h",
-    "src/core/lib/surface/channel_init.h",
-    "src/core/lib/surface/channel_stack_type.h",
-    "src/core/lib/surface/completion_queue.h",
-    "src/core/lib/surface/event_string.h",
-    "src/core/lib/surface/init.h",
-    "src/core/lib/surface/lame_client.h",
-    "src/core/lib/surface/server.h",
-    "src/core/lib/transport/byte_stream.h",
-    "src/core/lib/transport/connectivity_state.h",
-    "src/core/lib/transport/mdstr_hash_table.h",
-    "src/core/lib/transport/metadata.h",
-    "src/core/lib/transport/metadata_batch.h",
-    "src/core/lib/transport/pid_controller.h",
-    "src/core/lib/transport/service_config.h",
-    "src/core/lib/transport/static_metadata.h",
-    "src/core/lib/transport/timeout_encoding.h",
-    "src/core/lib/transport/transport.h",
-    "src/core/lib/transport/transport_impl.h",
-    "src/core/ext/transport/chttp2/alpn/alpn.h",
-    "src/core/ext/client_channel/client_channel.h",
-    "src/core/ext/client_channel/client_channel_factory.h",
-    "src/core/ext/client_channel/connector.h",
-    "src/core/ext/client_channel/http_connect_handshaker.h",
-    "src/core/ext/client_channel/initial_connect_string.h",
-    "src/core/ext/client_channel/lb_policy.h",
-    "src/core/ext/client_channel/lb_policy_factory.h",
-    "src/core/ext/client_channel/lb_policy_registry.h",
-    "src/core/ext/client_channel/parse_address.h",
-    "src/core/ext/client_channel/resolver.h",
-    "src/core/ext/client_channel/resolver_factory.h",
-    "src/core/ext/client_channel/resolver_registry.h",
-    "src/core/ext/client_channel/subchannel.h",
-    "src/core/ext/client_channel/subchannel_index.h",
-    "src/core/ext/client_channel/uri_parser.h",
-    "src/core/ext/transport/chttp2/server/chttp2_server.h",
-    "src/core/ext/census/aggregation.h",
-    "src/core/ext/census/base_resources.h",
-    "src/core/ext/census/census_interface.h",
-    "src/core/ext/census/census_rpc_stats.h",
-    "src/core/ext/census/gen/census.pb.h",
-    "src/core/ext/census/gen/trace_context.pb.h",
-    "src/core/ext/census/grpc_filter.h",
-    "src/core/ext/census/mlog.h",
-    "src/core/ext/census/resource.h",
-    "src/core/ext/census/rpc_metric_id.h",
-    "src/core/ext/census/trace_context.h",
-    "src/cpp/client/cronet_credentials.cc",
-    "src/cpp/client/insecure_credentials.cc",
-    "src/cpp/common/insecure_create_auth_context.cc",
-    "src/cpp/server/insecure_server_credentials.cc",
-    "src/cpp/client/channel_cc.cc",
-    "src/cpp/client/client_context.cc",
-    "src/cpp/client/create_channel.cc",
-    "src/cpp/client/create_channel_internal.cc",
-    "src/cpp/client/create_channel_posix.cc",
-    "src/cpp/client/credentials_cc.cc",
-    "src/cpp/client/generic_stub.cc",
-    "src/cpp/common/channel_arguments.cc",
-    "src/cpp/common/channel_filter.cc",
-    "src/cpp/common/completion_queue_cc.cc",
-    "src/cpp/common/core_codegen.cc",
-    "src/cpp/common/resource_quota_cc.cc",
-    "src/cpp/common/rpc_method.cc",
-    "src/cpp/common/version_cc.cc",
-    "src/cpp/server/async_generic_service.cc",
-    "src/cpp/server/create_default_thread_pool.cc",
-    "src/cpp/server/dynamic_thread_pool.cc",
-    "src/cpp/server/server_builder.cc",
-    "src/cpp/server/server_cc.cc",
-    "src/cpp/server/server_context.cc",
-    "src/cpp/server/server_credentials.cc",
-    "src/cpp/server/server_posix.cc",
-    "src/cpp/thread_manager/thread_manager.cc",
-    "src/cpp/util/byte_buffer_cc.cc",
-    "src/cpp/util/slice_cc.cc",
-    "src/cpp/util/status.cc",
-    "src/cpp/util/string_ref.cc",
-    "src/cpp/util/time_cc.cc",
-    "src/cpp/codegen/codegen_init.cc",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.c",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.c",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
-    "src/core/ext/transport/chttp2/transport/frame_data.c",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
-    "src/core/ext/transport/chttp2/transport/frame_ping.c",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
-    "src/core/ext/transport/chttp2/transport/frame_settings.c",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
-    "src/core/ext/transport/chttp2/transport/hpack_table.c",
-    "src/core/ext/transport/chttp2/transport/huffsyms.c",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
-    "src/core/ext/transport/chttp2/transport/parsing.c",
-    "src/core/ext/transport/chttp2/transport/status_conversion.c",
-    "src/core/ext/transport/chttp2/transport/stream_lists.c",
-    "src/core/ext/transport/chttp2/transport/stream_map.c",
-    "src/core/ext/transport/chttp2/transport/varint.c",
-    "src/core/ext/transport/chttp2/transport/writing.c",
-    "src/core/lib/channel/channel_args.c",
-    "src/core/lib/channel/channel_stack.c",
-    "src/core/lib/channel/channel_stack_builder.c",
-    "src/core/lib/channel/compress_filter.c",
-    "src/core/lib/channel/connected_channel.c",
-    "src/core/lib/channel/deadline_filter.c",
-    "src/core/lib/channel/handshaker.c",
-    "src/core/lib/channel/http_client_filter.c",
-    "src/core/lib/channel/http_server_filter.c",
-    "src/core/lib/channel/message_size_filter.c",
-    "src/core/lib/compression/compression.c",
-    "src/core/lib/compression/message_compress.c",
-    "src/core/lib/debug/trace.c",
-    "src/core/lib/http/format_request.c",
-    "src/core/lib/http/httpcli.c",
-    "src/core/lib/http/parser.c",
-    "src/core/lib/iomgr/closure.c",
-    "src/core/lib/iomgr/combiner.c",
-    "src/core/lib/iomgr/endpoint.c",
-    "src/core/lib/iomgr/endpoint_pair_posix.c",
-    "src/core/lib/iomgr/endpoint_pair_uv.c",
-    "src/core/lib/iomgr/endpoint_pair_windows.c",
-    "src/core/lib/iomgr/error.c",
-    "src/core/lib/iomgr/ev_epoll_linux.c",
-    "src/core/lib/iomgr/ev_poll_posix.c",
-    "src/core/lib/iomgr/ev_posix.c",
-    "src/core/lib/iomgr/exec_ctx.c",
-    "src/core/lib/iomgr/executor.c",
-    "src/core/lib/iomgr/iocp_windows.c",
-    "src/core/lib/iomgr/iomgr.c",
-    "src/core/lib/iomgr/iomgr_posix.c",
-    "src/core/lib/iomgr/iomgr_uv.c",
-    "src/core/lib/iomgr/iomgr_windows.c",
-    "src/core/lib/iomgr/load_file.c",
-    "src/core/lib/iomgr/network_status_tracker.c",
-    "src/core/lib/iomgr/polling_entity.c",
-    "src/core/lib/iomgr/pollset_set_uv.c",
-    "src/core/lib/iomgr/pollset_set_windows.c",
-    "src/core/lib/iomgr/pollset_uv.c",
-    "src/core/lib/iomgr/pollset_windows.c",
-    "src/core/lib/iomgr/resolve_address_posix.c",
-    "src/core/lib/iomgr/resolve_address_uv.c",
-    "src/core/lib/iomgr/resolve_address_windows.c",
-    "src/core/lib/iomgr/resource_quota.c",
-    "src/core/lib/iomgr/sockaddr_utils.c",
-    "src/core/lib/iomgr/socket_mutator.c",
-    "src/core/lib/iomgr/socket_utils_common_posix.c",
-    "src/core/lib/iomgr/socket_utils_linux.c",
-    "src/core/lib/iomgr/socket_utils_posix.c",
-    "src/core/lib/iomgr/socket_utils_uv.c",
-    "src/core/lib/iomgr/socket_utils_windows.c",
-    "src/core/lib/iomgr/socket_windows.c",
-    "src/core/lib/iomgr/tcp_client_posix.c",
-    "src/core/lib/iomgr/tcp_client_uv.c",
-    "src/core/lib/iomgr/tcp_client_windows.c",
-    "src/core/lib/iomgr/tcp_posix.c",
-    "src/core/lib/iomgr/tcp_server_posix.c",
-    "src/core/lib/iomgr/tcp_server_uv.c",
-    "src/core/lib/iomgr/tcp_server_windows.c",
-    "src/core/lib/iomgr/tcp_uv.c",
-    "src/core/lib/iomgr/tcp_windows.c",
-    "src/core/lib/iomgr/time_averaged_stats.c",
-    "src/core/lib/iomgr/timer_generic.c",
-    "src/core/lib/iomgr/timer_heap.c",
-    "src/core/lib/iomgr/timer_uv.c",
-    "src/core/lib/iomgr/udp_server.c",
-    "src/core/lib/iomgr/unix_sockets_posix.c",
-    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
-    "src/core/lib/iomgr/wakeup_fd_cv.c",
-    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
-    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
-    "src/core/lib/iomgr/wakeup_fd_pipe.c",
-    "src/core/lib/iomgr/wakeup_fd_posix.c",
-    "src/core/lib/iomgr/workqueue_uv.c",
-    "src/core/lib/iomgr/workqueue_windows.c",
-    "src/core/lib/json/json.c",
-    "src/core/lib/json/json_reader.c",
-    "src/core/lib/json/json_string.c",
-    "src/core/lib/json/json_writer.c",
-    "src/core/lib/slice/percent_encoding.c",
-    "src/core/lib/slice/slice.c",
-    "src/core/lib/slice/slice_buffer.c",
-    "src/core/lib/slice/slice_string_helpers.c",
-    "src/core/lib/surface/alarm.c",
-    "src/core/lib/surface/api_trace.c",
-    "src/core/lib/surface/byte_buffer.c",
-    "src/core/lib/surface/byte_buffer_reader.c",
-    "src/core/lib/surface/call.c",
-    "src/core/lib/surface/call_details.c",
-    "src/core/lib/surface/call_log_batch.c",
-    "src/core/lib/surface/channel.c",
-    "src/core/lib/surface/channel_init.c",
-    "src/core/lib/surface/channel_ping.c",
-    "src/core/lib/surface/channel_stack_type.c",
-    "src/core/lib/surface/completion_queue.c",
-    "src/core/lib/surface/event_string.c",
-    "src/core/lib/surface/lame_client.c",
-    "src/core/lib/surface/metadata_array.c",
-    "src/core/lib/surface/server.c",
-    "src/core/lib/surface/validate_metadata.c",
-    "src/core/lib/surface/version.c",
-    "src/core/lib/transport/byte_stream.c",
-    "src/core/lib/transport/connectivity_state.c",
-    "src/core/lib/transport/mdstr_hash_table.c",
-    "src/core/lib/transport/metadata.c",
-    "src/core/lib/transport/metadata_batch.c",
-    "src/core/lib/transport/pid_controller.c",
-    "src/core/lib/transport/service_config.c",
-    "src/core/lib/transport/static_metadata.c",
-    "src/core/lib/transport/timeout_encoding.c",
-    "src/core/lib/transport/transport.c",
-    "src/core/lib/transport/transport_op_string.c",
-    "src/core/ext/transport/chttp2/alpn/alpn.c",
-    "src/core/ext/client_channel/channel_connectivity.c",
-    "src/core/ext/client_channel/client_channel.c",
-    "src/core/ext/client_channel/client_channel_factory.c",
-    "src/core/ext/client_channel/client_channel_plugin.c",
-    "src/core/ext/client_channel/connector.c",
-    "src/core/ext/client_channel/default_initial_connect_string.c",
-    "src/core/ext/client_channel/http_connect_handshaker.c",
-    "src/core/ext/client_channel/initial_connect_string.c",
-    "src/core/ext/client_channel/lb_policy.c",
-    "src/core/ext/client_channel/lb_policy_factory.c",
-    "src/core/ext/client_channel/lb_policy_registry.c",
-    "src/core/ext/client_channel/parse_address.c",
-    "src/core/ext/client_channel/resolver.c",
-    "src/core/ext/client_channel/resolver_factory.c",
-    "src/core/ext/client_channel/resolver_registry.c",
-    "src/core/ext/client_channel/subchannel.c",
-    "src/core/ext/client_channel/subchannel_index.c",
-    "src/core/ext/client_channel/uri_parser.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
-    "src/core/ext/transport/chttp2/server/chttp2_server.c",
-    "src/core/ext/census/base_resources.c",
-    "src/core/ext/census/context.c",
-    "src/core/ext/census/gen/census.pb.c",
-    "src/core/ext/census/gen/trace_context.pb.c",
-    "src/core/ext/census/grpc_context.c",
-    "src/core/ext/census/grpc_filter.c",
-    "src/core/ext/census/grpc_plugin.c",
-    "src/core/ext/census/initialize.c",
-    "src/core/ext/census/mlog.c",
-    "src/core/ext/census/operation.c",
-    "src/core/ext/census/placeholders.c",
-    "src/core/ext/census/resource.c",
-    "src/core/ext/census/trace_context.c",
-    "src/core/ext/census/tracing.c",
-  ],
-  hdrs = [
-    "include/grpc++/alarm.h",
-    "include/grpc++/channel.h",
-    "include/grpc++/client_context.h",
-    "include/grpc++/completion_queue.h",
-    "include/grpc++/create_channel.h",
-    "include/grpc++/create_channel_posix.h",
-    "include/grpc++/generic/async_generic_service.h",
-    "include/grpc++/generic/generic_stub.h",
-    "include/grpc++/grpc++.h",
-    "include/grpc++/impl/call.h",
-    "include/grpc++/impl/client_unary_call.h",
-    "include/grpc++/impl/codegen/core_codegen.h",
-    "include/grpc++/impl/grpc_library.h",
-    "include/grpc++/impl/method_handler_impl.h",
-    "include/grpc++/impl/rpc_method.h",
-    "include/grpc++/impl/rpc_service_method.h",
-    "include/grpc++/impl/serialization_traits.h",
-    "include/grpc++/impl/server_builder_option.h",
-    "include/grpc++/impl/server_builder_plugin.h",
-    "include/grpc++/impl/server_initializer.h",
-    "include/grpc++/impl/service_type.h",
-    "include/grpc++/resource_quota.h",
-    "include/grpc++/security/auth_context.h",
-    "include/grpc++/security/auth_metadata_processor.h",
-    "include/grpc++/security/credentials.h",
-    "include/grpc++/security/server_credentials.h",
-    "include/grpc++/server.h",
-    "include/grpc++/server_builder.h",
-    "include/grpc++/server_context.h",
-    "include/grpc++/server_posix.h",
-    "include/grpc++/support/async_stream.h",
-    "include/grpc++/support/async_unary_call.h",
-    "include/grpc++/support/byte_buffer.h",
-    "include/grpc++/support/channel_arguments.h",
-    "include/grpc++/support/config.h",
-    "include/grpc++/support/slice.h",
-    "include/grpc++/support/status.h",
-    "include/grpc++/support/status_code_enum.h",
-    "include/grpc++/support/string_ref.h",
-    "include/grpc++/support/stub_options.h",
-    "include/grpc++/support/sync_stream.h",
-    "include/grpc++/support/time.h",
-    "include/grpc++/impl/codegen/async_stream.h",
-    "include/grpc++/impl/codegen/async_unary_call.h",
-    "include/grpc++/impl/codegen/call.h",
-    "include/grpc++/impl/codegen/call_hook.h",
-    "include/grpc++/impl/codegen/channel_interface.h",
-    "include/grpc++/impl/codegen/client_context.h",
-    "include/grpc++/impl/codegen/client_unary_call.h",
-    "include/grpc++/impl/codegen/completion_queue.h",
-    "include/grpc++/impl/codegen/completion_queue_tag.h",
-    "include/grpc++/impl/codegen/config.h",
-    "include/grpc++/impl/codegen/core_codegen_interface.h",
-    "include/grpc++/impl/codegen/create_auth_context.h",
-    "include/grpc++/impl/codegen/grpc_library.h",
-    "include/grpc++/impl/codegen/method_handler_impl.h",
-    "include/grpc++/impl/codegen/rpc_method.h",
-    "include/grpc++/impl/codegen/rpc_service_method.h",
-    "include/grpc++/impl/codegen/security/auth_context.h",
-    "include/grpc++/impl/codegen/serialization_traits.h",
-    "include/grpc++/impl/codegen/server_context.h",
-    "include/grpc++/impl/codegen/server_interface.h",
-    "include/grpc++/impl/codegen/service_type.h",
-    "include/grpc++/impl/codegen/status.h",
-    "include/grpc++/impl/codegen/status_code_enum.h",
-    "include/grpc++/impl/codegen/status_helper.h",
-    "include/grpc++/impl/codegen/string_ref.h",
-    "include/grpc++/impl/codegen/stub_options.h",
-    "include/grpc++/impl/codegen/sync_stream.h",
-    "include/grpc++/impl/codegen/time.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/byte_buffer.h",
-    "include/grpc/byte_buffer_reader.h",
-    "include/grpc/compression.h",
-    "include/grpc/grpc.h",
-    "include/grpc/grpc_posix.h",
-    "include/grpc/grpc_security_constants.h",
-    "include/grpc/slice.h",
-    "include/grpc/slice_buffer.h",
-    "include/grpc/status.h",
-    "include/grpc/census.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    "//external:libssl",
-    ":gpr",
-    ":grpc_cronet",
-    "//external:nanopb",
-  ],
+grpc_cc_library(
+    name = "grpc_transport_chttp2_server_insecure",
+    srcs = [
+        "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
+        "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_transport_chttp2",
+        "grpc_transport_chttp2_server",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc++_reflection",
-  srcs = [
-    "src/cpp/ext/proto_server_reflection.h",
-    "src/cpp/ext/proto_server_reflection.cc",
-    "src/cpp/ext/proto_server_reflection_plugin.cc",
-    "src/proto/grpc/reflection/v1alpha/reflection.proto",
-  ],
-  hdrs = [
-    "include/grpc++/ext/proto_server_reflection_plugin.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    ":grpc++",
-  ],
+grpc_cc_library(
+    name = "grpc_transport_chttp2_server_secure",
+    srcs = [
+        "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_secure",
+        "grpc_transport_chttp2",
+        "grpc_transport_chttp2_server",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc++_unsecure",
-  srcs = [
-    "src/cpp/client/create_channel_internal.h",
-    "src/cpp/common/channel_filter.h",
-    "src/cpp/server/dynamic_thread_pool.h",
-    "src/cpp/server/thread_pool_interface.h",
-    "src/cpp/thread_manager/thread_manager.h",
-    "src/cpp/client/insecure_credentials.cc",
-    "src/cpp/common/insecure_create_auth_context.cc",
-    "src/cpp/server/insecure_server_credentials.cc",
-    "src/cpp/client/channel_cc.cc",
-    "src/cpp/client/client_context.cc",
-    "src/cpp/client/create_channel.cc",
-    "src/cpp/client/create_channel_internal.cc",
-    "src/cpp/client/create_channel_posix.cc",
-    "src/cpp/client/credentials_cc.cc",
-    "src/cpp/client/generic_stub.cc",
-    "src/cpp/common/channel_arguments.cc",
-    "src/cpp/common/channel_filter.cc",
-    "src/cpp/common/completion_queue_cc.cc",
-    "src/cpp/common/core_codegen.cc",
-    "src/cpp/common/resource_quota_cc.cc",
-    "src/cpp/common/rpc_method.cc",
-    "src/cpp/common/version_cc.cc",
-    "src/cpp/server/async_generic_service.cc",
-    "src/cpp/server/create_default_thread_pool.cc",
-    "src/cpp/server/dynamic_thread_pool.cc",
-    "src/cpp/server/server_builder.cc",
-    "src/cpp/server/server_cc.cc",
-    "src/cpp/server/server_context.cc",
-    "src/cpp/server/server_credentials.cc",
-    "src/cpp/server/server_posix.cc",
-    "src/cpp/thread_manager/thread_manager.cc",
-    "src/cpp/util/byte_buffer_cc.cc",
-    "src/cpp/util/slice_cc.cc",
-    "src/cpp/util/status.cc",
-    "src/cpp/util/string_ref.cc",
-    "src/cpp/util/time_cc.cc",
-    "src/cpp/codegen/codegen_init.cc",
-  ],
-  hdrs = [
-    "include/grpc++/alarm.h",
-    "include/grpc++/channel.h",
-    "include/grpc++/client_context.h",
-    "include/grpc++/completion_queue.h",
-    "include/grpc++/create_channel.h",
-    "include/grpc++/create_channel_posix.h",
-    "include/grpc++/generic/async_generic_service.h",
-    "include/grpc++/generic/generic_stub.h",
-    "include/grpc++/grpc++.h",
-    "include/grpc++/impl/call.h",
-    "include/grpc++/impl/client_unary_call.h",
-    "include/grpc++/impl/codegen/core_codegen.h",
-    "include/grpc++/impl/grpc_library.h",
-    "include/grpc++/impl/method_handler_impl.h",
-    "include/grpc++/impl/rpc_method.h",
-    "include/grpc++/impl/rpc_service_method.h",
-    "include/grpc++/impl/serialization_traits.h",
-    "include/grpc++/impl/server_builder_option.h",
-    "include/grpc++/impl/server_builder_plugin.h",
-    "include/grpc++/impl/server_initializer.h",
-    "include/grpc++/impl/service_type.h",
-    "include/grpc++/resource_quota.h",
-    "include/grpc++/security/auth_context.h",
-    "include/grpc++/security/auth_metadata_processor.h",
-    "include/grpc++/security/credentials.h",
-    "include/grpc++/security/server_credentials.h",
-    "include/grpc++/server.h",
-    "include/grpc++/server_builder.h",
-    "include/grpc++/server_context.h",
-    "include/grpc++/server_posix.h",
-    "include/grpc++/support/async_stream.h",
-    "include/grpc++/support/async_unary_call.h",
-    "include/grpc++/support/byte_buffer.h",
-    "include/grpc++/support/channel_arguments.h",
-    "include/grpc++/support/config.h",
-    "include/grpc++/support/slice.h",
-    "include/grpc++/support/status.h",
-    "include/grpc++/support/status_code_enum.h",
-    "include/grpc++/support/string_ref.h",
-    "include/grpc++/support/stub_options.h",
-    "include/grpc++/support/sync_stream.h",
-    "include/grpc++/support/time.h",
-    "include/grpc++/impl/codegen/async_stream.h",
-    "include/grpc++/impl/codegen/async_unary_call.h",
-    "include/grpc++/impl/codegen/call.h",
-    "include/grpc++/impl/codegen/call_hook.h",
-    "include/grpc++/impl/codegen/channel_interface.h",
-    "include/grpc++/impl/codegen/client_context.h",
-    "include/grpc++/impl/codegen/client_unary_call.h",
-    "include/grpc++/impl/codegen/completion_queue.h",
-    "include/grpc++/impl/codegen/completion_queue_tag.h",
-    "include/grpc++/impl/codegen/config.h",
-    "include/grpc++/impl/codegen/core_codegen_interface.h",
-    "include/grpc++/impl/codegen/create_auth_context.h",
-    "include/grpc++/impl/codegen/grpc_library.h",
-    "include/grpc++/impl/codegen/method_handler_impl.h",
-    "include/grpc++/impl/codegen/rpc_method.h",
-    "include/grpc++/impl/codegen/rpc_service_method.h",
-    "include/grpc++/impl/codegen/security/auth_context.h",
-    "include/grpc++/impl/codegen/serialization_traits.h",
-    "include/grpc++/impl/codegen/server_context.h",
-    "include/grpc++/impl/codegen/server_interface.h",
-    "include/grpc++/impl/codegen/service_type.h",
-    "include/grpc++/impl/codegen/status.h",
-    "include/grpc++/impl/codegen/status_code_enum.h",
-    "include/grpc++/impl/codegen/status_helper.h",
-    "include/grpc++/impl/codegen/string_ref.h",
-    "include/grpc++/impl/codegen/stub_options.h",
-    "include/grpc++/impl/codegen/sync_stream.h",
-    "include/grpc++/impl/codegen/time.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    "//external:protobuf_clib",
-    ":gpr",
-    ":grpc_unsecure",
-  ],
+grpc_cc_library(
+    name = "grpc_transport_cronet_client_secure",
+    srcs = [
+        "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c",
+        "src/core/ext/transport/cronet/transport/cronet_api_dummy.c",
+        "src/core/ext/transport/cronet/transport/cronet_transport.c",
+    ],
+    hdrs = [
+        "third_party/objective_c/Cronet/cronet_c_for_grpc.h",
+    ],
+    language = "c",
+    public_hdrs = [
+        "include/grpc/grpc_cronet.h",
+        "include/grpc/grpc_security.h",
+        "include/grpc/grpc_security_constants.h",
+    ],
+    deps = [
+        "grpc_base",
+        "grpc_transport_chttp2",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc_plugin_support",
-  srcs = [
-    "src/compiler/config.h",
-    "src/compiler/cpp_generator.h",
-    "src/compiler/cpp_generator_helpers.h",
-    "src/compiler/csharp_generator.h",
-    "src/compiler/csharp_generator_helpers.h",
-    "src/compiler/generator_helpers.h",
-    "src/compiler/node_generator.h",
-    "src/compiler/node_generator_helpers.h",
-    "src/compiler/objective_c_generator.h",
-    "src/compiler/objective_c_generator_helpers.h",
-    "src/compiler/php_generator.h",
-    "src/compiler/php_generator_helpers.h",
-    "src/compiler/python_generator.h",
-    "src/compiler/ruby_generator.h",
-    "src/compiler/ruby_generator_helpers-inl.h",
-    "src/compiler/ruby_generator_map-inl.h",
-    "src/compiler/ruby_generator_string-inl.h",
-    "src/compiler/cpp_generator.cc",
-    "src/compiler/csharp_generator.cc",
-    "src/compiler/node_generator.cc",
-    "src/compiler/objective_c_generator.cc",
-    "src/compiler/php_generator.cc",
-    "src/compiler/python_generator.cc",
-    "src/compiler/ruby_generator.cc",
-  ],
-  hdrs = [
-    "include/grpc++/impl/codegen/config_protobuf.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-  ],
+grpc_cc_library(
+    name = "tsi",
+    srcs = [
+        "src/core/lib/tsi/fake_transport_security.c",
+        "src/core/lib/tsi/ssl_transport_security.c",
+        "src/core/lib/tsi/transport_security.c",
+    ],
+    hdrs = [
+        "src/core/lib/tsi/fake_transport_security.h",
+        "src/core/lib/tsi/ssl_transport_security.h",
+        "src/core/lib/tsi/ssl_types.h",
+        "src/core/lib/tsi/transport_security.h",
+        "src/core/lib/tsi/transport_security_interface.h",
+    ],
+    external_deps = [
+        "libssl",
+    ],
+    language = "c",
+    deps = [
+        "gpr",
+    ],
 )
 
-
-
-cc_library(
-  name = "grpc_csharp_ext",
-  srcs = [
-    "src/csharp/ext/grpc_csharp_ext.c",
-  ],
-  hdrs = [
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    ":grpc",
-    ":gpr",
-  ],
+grpc_cc_library(
+    name = "grpc++_base",
+    srcs = [
+        "src/cpp/client/channel_cc.cc",
+        "src/cpp/client/client_context.cc",
+        "src/cpp/client/create_channel.cc",
+        "src/cpp/client/create_channel_internal.cc",
+        "src/cpp/client/create_channel_posix.cc",
+        "src/cpp/client/credentials_cc.cc",
+        "src/cpp/client/generic_stub.cc",
+        "src/cpp/common/channel_arguments.cc",
+        "src/cpp/common/channel_filter.cc",
+        "src/cpp/common/completion_queue_cc.cc",
+        "src/cpp/common/core_codegen.cc",
+        "src/cpp/common/rpc_method.cc",
+        "src/cpp/server/async_generic_service.cc",
+        "src/cpp/server/create_default_thread_pool.cc",
+        "src/cpp/server/dynamic_thread_pool.cc",
+        "src/cpp/server/server_builder.cc",
+        "src/cpp/server/server_cc.cc",
+        "src/cpp/server/server_context.cc",
+        "src/cpp/server/server_credentials.cc",
+        "src/cpp/server/server_posix.cc",
+        "src/cpp/util/byte_buffer_cc.cc",
+        "src/cpp/util/slice_cc.cc",
+        "src/cpp/util/status.cc",
+        "src/cpp/util/string_ref.cc",
+        "src/cpp/util/time_cc.cc",
+    ],
+    hdrs = [
+        "src/cpp/client/create_channel_internal.h",
+        "src/cpp/common/channel_filter.h",
+        "src/cpp/server/dynamic_thread_pool.h",
+        "src/cpp/server/thread_pool_interface.h",
+        "src/cpp/thread_manager/thread_manager.h",
+    ],
+    language = "c++",
+    public_hdrs = [
+        "include/grpc++/alarm.h",
+        "include/grpc++/channel.h",
+        "include/grpc++/client_context.h",
+        "include/grpc++/completion_queue.h",
+        "include/grpc++/create_channel.h",
+        "include/grpc++/create_channel_posix.h",
+        "include/grpc++/generic/async_generic_service.h",
+        "include/grpc++/generic/generic_stub.h",
+        "include/grpc++/grpc++.h",
+        "include/grpc++/impl/call.h",
+        "include/grpc++/impl/client_unary_call.h",
+        "include/grpc++/impl/codegen/core_codegen.h",
+        "include/grpc++/impl/grpc_library.h",
+        "include/grpc++/impl/method_handler_impl.h",
+        "include/grpc++/impl/rpc_method.h",
+        "include/grpc++/impl/rpc_service_method.h",
+        "include/grpc++/impl/serialization_traits.h",
+        "include/grpc++/impl/server_builder_option.h",
+        "include/grpc++/impl/server_builder_plugin.h",
+        "include/grpc++/impl/server_initializer.h",
+        "include/grpc++/impl/service_type.h",
+        "include/grpc++/impl/sync_cxx11.h",
+        "include/grpc++/impl/sync_no_cxx11.h",
+        "include/grpc++/resource_quota.h",
+        "include/grpc++/security/auth_context.h",
+        "include/grpc++/security/auth_metadata_processor.h",
+        "include/grpc++/security/credentials.h",
+        "include/grpc++/security/server_credentials.h",
+        "include/grpc++/server.h",
+        "include/grpc++/server_builder.h",
+        "include/grpc++/server_context.h",
+        "include/grpc++/server_posix.h",
+        "include/grpc++/support/async_stream.h",
+        "include/grpc++/support/async_unary_call.h",
+        "include/grpc++/support/byte_buffer.h",
+        "include/grpc++/support/channel_arguments.h",
+        "include/grpc++/support/config.h",
+        "include/grpc++/support/slice.h",
+        "include/grpc++/support/status.h",
+        "include/grpc++/support/status_code_enum.h",
+        "include/grpc++/support/string_ref.h",
+        "include/grpc++/support/stub_options.h",
+        "include/grpc++/support/sync_stream.h",
+        "include/grpc++/support/time.h",
+    ],
+    deps = [
+        "grpc",
+        "grpc++_codegen_base",
+    ],
 )
 
-
-
-
-objc_library(
-  name = "gpr_objc",
-  srcs = [
-    "src/core/lib/profiling/basic_timers.c",
-    "src/core/lib/profiling/stap_timers.c",
-    "src/core/lib/support/alloc.c",
-    "src/core/lib/support/avl.c",
-    "src/core/lib/support/backoff.c",
-    "src/core/lib/support/cmdline.c",
-    "src/core/lib/support/cpu_iphone.c",
-    "src/core/lib/support/cpu_linux.c",
-    "src/core/lib/support/cpu_posix.c",
-    "src/core/lib/support/cpu_windows.c",
-    "src/core/lib/support/env_linux.c",
-    "src/core/lib/support/env_posix.c",
-    "src/core/lib/support/env_windows.c",
-    "src/core/lib/support/histogram.c",
-    "src/core/lib/support/host_port.c",
-    "src/core/lib/support/log.c",
-    "src/core/lib/support/log_android.c",
-    "src/core/lib/support/log_linux.c",
-    "src/core/lib/support/log_posix.c",
-    "src/core/lib/support/log_windows.c",
-    "src/core/lib/support/mpscq.c",
-    "src/core/lib/support/murmur_hash.c",
-    "src/core/lib/support/stack_lockfree.c",
-    "src/core/lib/support/string.c",
-    "src/core/lib/support/string_posix.c",
-    "src/core/lib/support/string_util_windows.c",
-    "src/core/lib/support/string_windows.c",
-    "src/core/lib/support/subprocess_posix.c",
-    "src/core/lib/support/subprocess_windows.c",
-    "src/core/lib/support/sync.c",
-    "src/core/lib/support/sync_posix.c",
-    "src/core/lib/support/sync_windows.c",
-    "src/core/lib/support/thd.c",
-    "src/core/lib/support/thd_posix.c",
-    "src/core/lib/support/thd_windows.c",
-    "src/core/lib/support/time.c",
-    "src/core/lib/support/time_posix.c",
-    "src/core/lib/support/time_precise.c",
-    "src/core/lib/support/time_windows.c",
-    "src/core/lib/support/tls_pthread.c",
-    "src/core/lib/support/tmpfile_msys.c",
-    "src/core/lib/support/tmpfile_posix.c",
-    "src/core/lib/support/tmpfile_windows.c",
-    "src/core/lib/support/wrap_memcpy.c",
-  ],
-  hdrs = [
-    "include/grpc/support/alloc.h",
-    "include/grpc/support/atm.h",
-    "include/grpc/support/atm_gcc_atomic.h",
-    "include/grpc/support/atm_gcc_sync.h",
-    "include/grpc/support/atm_windows.h",
-    "include/grpc/support/avl.h",
-    "include/grpc/support/cmdline.h",
-    "include/grpc/support/cpu.h",
-    "include/grpc/support/histogram.h",
-    "include/grpc/support/host_port.h",
-    "include/grpc/support/log.h",
-    "include/grpc/support/log_windows.h",
-    "include/grpc/support/port_platform.h",
-    "include/grpc/support/string_util.h",
-    "include/grpc/support/subprocess.h",
-    "include/grpc/support/sync.h",
-    "include/grpc/support/sync_generic.h",
-    "include/grpc/support/sync_posix.h",
-    "include/grpc/support/sync_windows.h",
-    "include/grpc/support/thd.h",
-    "include/grpc/support/time.h",
-    "include/grpc/support/tls.h",
-    "include/grpc/support/tls_gcc.h",
-    "include/grpc/support/tls_msvc.h",
-    "include/grpc/support/tls_pthread.h",
-    "include/grpc/support/useful.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "src/core/lib/profiling/timers.h",
-    "src/core/lib/support/backoff.h",
-    "src/core/lib/support/block_annotate.h",
-    "src/core/lib/support/env.h",
-    "src/core/lib/support/mpscq.h",
-    "src/core/lib/support/murmur_hash.h",
-    "src/core/lib/support/stack_lockfree.h",
-    "src/core/lib/support/string.h",
-    "src/core/lib/support/string_windows.h",
-    "src/core/lib/support/thd_internal.h",
-    "src/core/lib/support/time_precise.h",
-    "src/core/lib/support/tmpfile.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-  ],
+grpc_cc_library(
+    name = "grpc++_codegen_base",
+    language = "c++",
+    public_hdrs = [
+        "include/grpc++/impl/codegen/async_stream.h",
+        "include/grpc++/impl/codegen/async_unary_call.h",
+        "include/grpc++/impl/codegen/call.h",
+        "include/grpc++/impl/codegen/call_hook.h",
+        "include/grpc++/impl/codegen/channel_interface.h",
+        "include/grpc++/impl/codegen/client_context.h",
+        "include/grpc++/impl/codegen/client_unary_call.h",
+        "include/grpc++/impl/codegen/completion_queue.h",
+        "include/grpc++/impl/codegen/completion_queue_tag.h",
+        "include/grpc++/impl/codegen/config.h",
+        "include/grpc++/impl/codegen/core_codegen_interface.h",
+        "include/grpc++/impl/codegen/create_auth_context.h",
+        "include/grpc++/impl/codegen/grpc_library.h",
+        "include/grpc++/impl/codegen/method_handler_impl.h",
+        "include/grpc++/impl/codegen/rpc_method.h",
+        "include/grpc++/impl/codegen/rpc_service_method.h",
+        "include/grpc++/impl/codegen/security/auth_context.h",
+        "include/grpc++/impl/codegen/serialization_traits.h",
+        "include/grpc++/impl/codegen/server_context.h",
+        "include/grpc++/impl/codegen/server_interface.h",
+        "include/grpc++/impl/codegen/service_type.h",
+        "include/grpc++/impl/codegen/status.h",
+        "include/grpc++/impl/codegen/status_code_enum.h",
+        "include/grpc++/impl/codegen/status_helper.h",
+        "include/grpc++/impl/codegen/string_ref.h",
+        "include/grpc++/impl/codegen/stub_options.h",
+        "include/grpc++/impl/codegen/sync_stream.h",
+        "include/grpc++/impl/codegen/time.h",
+    ],
+    deps = [
+        "grpc_codegen",
+    ],
 )
 
-
-
-objc_library(
-  name = "grpc_objc",
-  srcs = [
-    "src/core/lib/surface/init.c",
-    "src/core/lib/channel/channel_args.c",
-    "src/core/lib/channel/channel_stack.c",
-    "src/core/lib/channel/channel_stack_builder.c",
-    "src/core/lib/channel/compress_filter.c",
-    "src/core/lib/channel/connected_channel.c",
-    "src/core/lib/channel/deadline_filter.c",
-    "src/core/lib/channel/handshaker.c",
-    "src/core/lib/channel/http_client_filter.c",
-    "src/core/lib/channel/http_server_filter.c",
-    "src/core/lib/channel/message_size_filter.c",
-    "src/core/lib/compression/compression.c",
-    "src/core/lib/compression/message_compress.c",
-    "src/core/lib/debug/trace.c",
-    "src/core/lib/http/format_request.c",
-    "src/core/lib/http/httpcli.c",
-    "src/core/lib/http/parser.c",
-    "src/core/lib/iomgr/closure.c",
-    "src/core/lib/iomgr/combiner.c",
-    "src/core/lib/iomgr/endpoint.c",
-    "src/core/lib/iomgr/endpoint_pair_posix.c",
-    "src/core/lib/iomgr/endpoint_pair_uv.c",
-    "src/core/lib/iomgr/endpoint_pair_windows.c",
-    "src/core/lib/iomgr/error.c",
-    "src/core/lib/iomgr/ev_epoll_linux.c",
-    "src/core/lib/iomgr/ev_poll_posix.c",
-    "src/core/lib/iomgr/ev_posix.c",
-    "src/core/lib/iomgr/exec_ctx.c",
-    "src/core/lib/iomgr/executor.c",
-    "src/core/lib/iomgr/iocp_windows.c",
-    "src/core/lib/iomgr/iomgr.c",
-    "src/core/lib/iomgr/iomgr_posix.c",
-    "src/core/lib/iomgr/iomgr_uv.c",
-    "src/core/lib/iomgr/iomgr_windows.c",
-    "src/core/lib/iomgr/load_file.c",
-    "src/core/lib/iomgr/network_status_tracker.c",
-    "src/core/lib/iomgr/polling_entity.c",
-    "src/core/lib/iomgr/pollset_set_uv.c",
-    "src/core/lib/iomgr/pollset_set_windows.c",
-    "src/core/lib/iomgr/pollset_uv.c",
-    "src/core/lib/iomgr/pollset_windows.c",
-    "src/core/lib/iomgr/resolve_address_posix.c",
-    "src/core/lib/iomgr/resolve_address_uv.c",
-    "src/core/lib/iomgr/resolve_address_windows.c",
-    "src/core/lib/iomgr/resource_quota.c",
-    "src/core/lib/iomgr/sockaddr_utils.c",
-    "src/core/lib/iomgr/socket_mutator.c",
-    "src/core/lib/iomgr/socket_utils_common_posix.c",
-    "src/core/lib/iomgr/socket_utils_linux.c",
-    "src/core/lib/iomgr/socket_utils_posix.c",
-    "src/core/lib/iomgr/socket_utils_uv.c",
-    "src/core/lib/iomgr/socket_utils_windows.c",
-    "src/core/lib/iomgr/socket_windows.c",
-    "src/core/lib/iomgr/tcp_client_posix.c",
-    "src/core/lib/iomgr/tcp_client_uv.c",
-    "src/core/lib/iomgr/tcp_client_windows.c",
-    "src/core/lib/iomgr/tcp_posix.c",
-    "src/core/lib/iomgr/tcp_server_posix.c",
-    "src/core/lib/iomgr/tcp_server_uv.c",
-    "src/core/lib/iomgr/tcp_server_windows.c",
-    "src/core/lib/iomgr/tcp_uv.c",
-    "src/core/lib/iomgr/tcp_windows.c",
-    "src/core/lib/iomgr/time_averaged_stats.c",
-    "src/core/lib/iomgr/timer_generic.c",
-    "src/core/lib/iomgr/timer_heap.c",
-    "src/core/lib/iomgr/timer_uv.c",
-    "src/core/lib/iomgr/udp_server.c",
-    "src/core/lib/iomgr/unix_sockets_posix.c",
-    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
-    "src/core/lib/iomgr/wakeup_fd_cv.c",
-    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
-    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
-    "src/core/lib/iomgr/wakeup_fd_pipe.c",
-    "src/core/lib/iomgr/wakeup_fd_posix.c",
-    "src/core/lib/iomgr/workqueue_uv.c",
-    "src/core/lib/iomgr/workqueue_windows.c",
-    "src/core/lib/json/json.c",
-    "src/core/lib/json/json_reader.c",
-    "src/core/lib/json/json_string.c",
-    "src/core/lib/json/json_writer.c",
-    "src/core/lib/slice/percent_encoding.c",
-    "src/core/lib/slice/slice.c",
-    "src/core/lib/slice/slice_buffer.c",
-    "src/core/lib/slice/slice_string_helpers.c",
-    "src/core/lib/surface/alarm.c",
-    "src/core/lib/surface/api_trace.c",
-    "src/core/lib/surface/byte_buffer.c",
-    "src/core/lib/surface/byte_buffer_reader.c",
-    "src/core/lib/surface/call.c",
-    "src/core/lib/surface/call_details.c",
-    "src/core/lib/surface/call_log_batch.c",
-    "src/core/lib/surface/channel.c",
-    "src/core/lib/surface/channel_init.c",
-    "src/core/lib/surface/channel_ping.c",
-    "src/core/lib/surface/channel_stack_type.c",
-    "src/core/lib/surface/completion_queue.c",
-    "src/core/lib/surface/event_string.c",
-    "src/core/lib/surface/lame_client.c",
-    "src/core/lib/surface/metadata_array.c",
-    "src/core/lib/surface/server.c",
-    "src/core/lib/surface/validate_metadata.c",
-    "src/core/lib/surface/version.c",
-    "src/core/lib/transport/byte_stream.c",
-    "src/core/lib/transport/connectivity_state.c",
-    "src/core/lib/transport/mdstr_hash_table.c",
-    "src/core/lib/transport/metadata.c",
-    "src/core/lib/transport/metadata_batch.c",
-    "src/core/lib/transport/pid_controller.c",
-    "src/core/lib/transport/service_config.c",
-    "src/core/lib/transport/static_metadata.c",
-    "src/core/lib/transport/timeout_encoding.c",
-    "src/core/lib/transport/transport.c",
-    "src/core/lib/transport/transport_op_string.c",
-    "src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.c",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_plugin.c",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.c",
-    "src/core/ext/transport/chttp2/transport/frame_data.c",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.c",
-    "src/core/ext/transport/chttp2/transport/frame_ping.c",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.c",
-    "src/core/ext/transport/chttp2/transport/frame_settings.c",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.c",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.c",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.c",
-    "src/core/ext/transport/chttp2/transport/hpack_table.c",
-    "src/core/ext/transport/chttp2/transport/huffsyms.c",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.c",
-    "src/core/ext/transport/chttp2/transport/parsing.c",
-    "src/core/ext/transport/chttp2/transport/status_conversion.c",
-    "src/core/ext/transport/chttp2/transport/stream_lists.c",
-    "src/core/ext/transport/chttp2/transport/stream_map.c",
-    "src/core/ext/transport/chttp2/transport/varint.c",
-    "src/core/ext/transport/chttp2/transport/writing.c",
-    "src/core/ext/transport/chttp2/alpn/alpn.c",
-    "src/core/lib/http/httpcli_security_connector.c",
-    "src/core/lib/security/context/security_context.c",
-    "src/core/lib/security/credentials/composite/composite_credentials.c",
-    "src/core/lib/security/credentials/credentials.c",
-    "src/core/lib/security/credentials/credentials_metadata.c",
-    "src/core/lib/security/credentials/fake/fake_credentials.c",
-    "src/core/lib/security/credentials/google_default/credentials_generic.c",
-    "src/core/lib/security/credentials/google_default/google_default_credentials.c",
-    "src/core/lib/security/credentials/iam/iam_credentials.c",
-    "src/core/lib/security/credentials/jwt/json_token.c",
-    "src/core/lib/security/credentials/jwt/jwt_credentials.c",
-    "src/core/lib/security/credentials/jwt/jwt_verifier.c",
-    "src/core/lib/security/credentials/oauth2/oauth2_credentials.c",
-    "src/core/lib/security/credentials/plugin/plugin_credentials.c",
-    "src/core/lib/security/credentials/ssl/ssl_credentials.c",
-    "src/core/lib/security/transport/client_auth_filter.c",
-    "src/core/lib/security/transport/secure_endpoint.c",
-    "src/core/lib/security/transport/security_connector.c",
-    "src/core/lib/security/transport/security_handshaker.c",
-    "src/core/lib/security/transport/server_auth_filter.c",
-    "src/core/lib/security/transport/tsi_error.c",
-    "src/core/lib/security/util/b64.c",
-    "src/core/lib/security/util/json_util.c",
-    "src/core/lib/surface/init_secure.c",
-    "src/core/lib/tsi/fake_transport_security.c",
-    "src/core/lib/tsi/ssl_transport_security.c",
-    "src/core/lib/tsi/transport_security.c",
-    "src/core/ext/transport/chttp2/server/chttp2_server.c",
-    "src/core/ext/transport/chttp2/client/secure/secure_channel_create.c",
-    "src/core/ext/client_channel/channel_connectivity.c",
-    "src/core/ext/client_channel/client_channel.c",
-    "src/core/ext/client_channel/client_channel_factory.c",
-    "src/core/ext/client_channel/client_channel_plugin.c",
-    "src/core/ext/client_channel/connector.c",
-    "src/core/ext/client_channel/default_initial_connect_string.c",
-    "src/core/ext/client_channel/http_connect_handshaker.c",
-    "src/core/ext/client_channel/initial_connect_string.c",
-    "src/core/ext/client_channel/lb_policy.c",
-    "src/core/ext/client_channel/lb_policy_factory.c",
-    "src/core/ext/client_channel/lb_policy_registry.c",
-    "src/core/ext/client_channel/parse_address.c",
-    "src/core/ext/client_channel/resolver.c",
-    "src/core/ext/client_channel/resolver_factory.c",
-    "src/core/ext/client_channel/resolver_registry.c",
-    "src/core/ext/client_channel/subchannel.c",
-    "src/core/ext/client_channel/subchannel_index.c",
-    "src/core/ext/client_channel/uri_parser.c",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
-    "src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create.c",
-    "src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c",
-    "src/core/ext/lb_policy/grpclb/grpclb.c",
-    "src/core/ext/lb_policy/grpclb/load_balancer_api.c",
-    "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c",
-    "src/core/ext/lb_policy/pick_first/pick_first.c",
-    "src/core/ext/lb_policy/round_robin/round_robin.c",
-    "src/core/ext/resolver/dns/native/dns_resolver.c",
-    "src/core/ext/resolver/sockaddr/sockaddr_resolver.c",
-    "src/core/ext/load_reporting/load_reporting.c",
-    "src/core/ext/load_reporting/load_reporting_filter.c",
-    "src/core/ext/census/base_resources.c",
-    "src/core/ext/census/context.c",
-    "src/core/ext/census/gen/census.pb.c",
-    "src/core/ext/census/gen/trace_context.pb.c",
-    "src/core/ext/census/grpc_context.c",
-    "src/core/ext/census/grpc_filter.c",
-    "src/core/ext/census/grpc_plugin.c",
-    "src/core/ext/census/initialize.c",
-    "src/core/ext/census/mlog.c",
-    "src/core/ext/census/operation.c",
-    "src/core/ext/census/placeholders.c",
-    "src/core/ext/census/resource.c",
-    "src/core/ext/census/trace_context.c",
-    "src/core/ext/census/tracing.c",
-    "src/core/plugin_registry/grpc_plugin_registry.c",
-  ],
-  hdrs = [
-    "include/grpc/byte_buffer.h",
-    "include/grpc/byte_buffer_reader.h",
-    "include/grpc/compression.h",
-    "include/grpc/grpc.h",
-    "include/grpc/grpc_posix.h",
-    "include/grpc/grpc_security_constants.h",
-    "include/grpc/slice.h",
-    "include/grpc/slice_buffer.h",
-    "include/grpc/status.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/gpr_types.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/grpc_security.h",
-    "include/grpc/census.h",
-    "src/core/lib/channel/channel_args.h",
-    "src/core/lib/channel/channel_stack.h",
-    "src/core/lib/channel/channel_stack_builder.h",
-    "src/core/lib/channel/compress_filter.h",
-    "src/core/lib/channel/connected_channel.h",
-    "src/core/lib/channel/context.h",
-    "src/core/lib/channel/deadline_filter.h",
-    "src/core/lib/channel/handshaker.h",
-    "src/core/lib/channel/http_client_filter.h",
-    "src/core/lib/channel/http_server_filter.h",
-    "src/core/lib/channel/message_size_filter.h",
-    "src/core/lib/compression/algorithm_metadata.h",
-    "src/core/lib/compression/message_compress.h",
-    "src/core/lib/debug/trace.h",
-    "src/core/lib/http/format_request.h",
-    "src/core/lib/http/httpcli.h",
-    "src/core/lib/http/parser.h",
-    "src/core/lib/iomgr/closure.h",
-    "src/core/lib/iomgr/combiner.h",
-    "src/core/lib/iomgr/endpoint.h",
-    "src/core/lib/iomgr/endpoint_pair.h",
-    "src/core/lib/iomgr/error.h",
-    "src/core/lib/iomgr/ev_epoll_linux.h",
-    "src/core/lib/iomgr/ev_poll_posix.h",
-    "src/core/lib/iomgr/ev_posix.h",
-    "src/core/lib/iomgr/exec_ctx.h",
-    "src/core/lib/iomgr/executor.h",
-    "src/core/lib/iomgr/iocp_windows.h",
-    "src/core/lib/iomgr/iomgr.h",
-    "src/core/lib/iomgr/iomgr_internal.h",
-    "src/core/lib/iomgr/iomgr_posix.h",
-    "src/core/lib/iomgr/load_file.h",
-    "src/core/lib/iomgr/network_status_tracker.h",
-    "src/core/lib/iomgr/polling_entity.h",
-    "src/core/lib/iomgr/pollset.h",
-    "src/core/lib/iomgr/pollset_set.h",
-    "src/core/lib/iomgr/pollset_set_windows.h",
-    "src/core/lib/iomgr/pollset_uv.h",
-    "src/core/lib/iomgr/pollset_windows.h",
-    "src/core/lib/iomgr/port.h",
-    "src/core/lib/iomgr/resolve_address.h",
-    "src/core/lib/iomgr/resource_quota.h",
-    "src/core/lib/iomgr/sockaddr.h",
-    "src/core/lib/iomgr/sockaddr_posix.h",
-    "src/core/lib/iomgr/sockaddr_utils.h",
-    "src/core/lib/iomgr/sockaddr_windows.h",
-    "src/core/lib/iomgr/socket_mutator.h",
-    "src/core/lib/iomgr/socket_utils.h",
-    "src/core/lib/iomgr/socket_utils_posix.h",
-    "src/core/lib/iomgr/socket_windows.h",
-    "src/core/lib/iomgr/tcp_client.h",
-    "src/core/lib/iomgr/tcp_client_posix.h",
-    "src/core/lib/iomgr/tcp_posix.h",
-    "src/core/lib/iomgr/tcp_server.h",
-    "src/core/lib/iomgr/tcp_uv.h",
-    "src/core/lib/iomgr/tcp_windows.h",
-    "src/core/lib/iomgr/time_averaged_stats.h",
-    "src/core/lib/iomgr/timer.h",
-    "src/core/lib/iomgr/timer_generic.h",
-    "src/core/lib/iomgr/timer_heap.h",
-    "src/core/lib/iomgr/timer_uv.h",
-    "src/core/lib/iomgr/udp_server.h",
-    "src/core/lib/iomgr/unix_sockets_posix.h",
-    "src/core/lib/iomgr/wakeup_fd_cv.h",
-    "src/core/lib/iomgr/wakeup_fd_pipe.h",
-    "src/core/lib/iomgr/wakeup_fd_posix.h",
-    "src/core/lib/iomgr/workqueue.h",
-    "src/core/lib/iomgr/workqueue_uv.h",
-    "src/core/lib/iomgr/workqueue_windows.h",
-    "src/core/lib/json/json.h",
-    "src/core/lib/json/json_common.h",
-    "src/core/lib/json/json_reader.h",
-    "src/core/lib/json/json_writer.h",
-    "src/core/lib/slice/percent_encoding.h",
-    "src/core/lib/slice/slice_string_helpers.h",
-    "src/core/lib/surface/api_trace.h",
-    "src/core/lib/surface/call.h",
-    "src/core/lib/surface/call_test_only.h",
-    "src/core/lib/surface/channel.h",
-    "src/core/lib/surface/channel_init.h",
-    "src/core/lib/surface/channel_stack_type.h",
-    "src/core/lib/surface/completion_queue.h",
-    "src/core/lib/surface/event_string.h",
-    "src/core/lib/surface/init.h",
-    "src/core/lib/surface/lame_client.h",
-    "src/core/lib/surface/server.h",
-    "src/core/lib/transport/byte_stream.h",
-    "src/core/lib/transport/connectivity_state.h",
-    "src/core/lib/transport/mdstr_hash_table.h",
-    "src/core/lib/transport/metadata.h",
-    "src/core/lib/transport/metadata_batch.h",
-    "src/core/lib/transport/pid_controller.h",
-    "src/core/lib/transport/service_config.h",
-    "src/core/lib/transport/static_metadata.h",
-    "src/core/lib/transport/timeout_encoding.h",
-    "src/core/lib/transport/transport.h",
-    "src/core/lib/transport/transport_impl.h",
-    "src/core/ext/transport/chttp2/transport/bin_decoder.h",
-    "src/core/ext/transport/chttp2/transport/bin_encoder.h",
-    "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
-    "src/core/ext/transport/chttp2/transport/frame.h",
-    "src/core/ext/transport/chttp2/transport/frame_data.h",
-    "src/core/ext/transport/chttp2/transport/frame_goaway.h",
-    "src/core/ext/transport/chttp2/transport/frame_ping.h",
-    "src/core/ext/transport/chttp2/transport/frame_rst_stream.h",
-    "src/core/ext/transport/chttp2/transport/frame_settings.h",
-    "src/core/ext/transport/chttp2/transport/frame_window_update.h",
-    "src/core/ext/transport/chttp2/transport/hpack_encoder.h",
-    "src/core/ext/transport/chttp2/transport/hpack_parser.h",
-    "src/core/ext/transport/chttp2/transport/hpack_table.h",
-    "src/core/ext/transport/chttp2/transport/http2_errors.h",
-    "src/core/ext/transport/chttp2/transport/huffsyms.h",
-    "src/core/ext/transport/chttp2/transport/incoming_metadata.h",
-    "src/core/ext/transport/chttp2/transport/internal.h",
-    "src/core/ext/transport/chttp2/transport/status_conversion.h",
-    "src/core/ext/transport/chttp2/transport/stream_map.h",
-    "src/core/ext/transport/chttp2/transport/varint.h",
-    "src/core/ext/transport/chttp2/alpn/alpn.h",
-    "src/core/lib/security/context/security_context.h",
-    "src/core/lib/security/credentials/composite/composite_credentials.h",
-    "src/core/lib/security/credentials/credentials.h",
-    "src/core/lib/security/credentials/fake/fake_credentials.h",
-    "src/core/lib/security/credentials/google_default/google_default_credentials.h",
-    "src/core/lib/security/credentials/iam/iam_credentials.h",
-    "src/core/lib/security/credentials/jwt/json_token.h",
-    "src/core/lib/security/credentials/jwt/jwt_credentials.h",
-    "src/core/lib/security/credentials/jwt/jwt_verifier.h",
-    "src/core/lib/security/credentials/oauth2/oauth2_credentials.h",
-    "src/core/lib/security/credentials/plugin/plugin_credentials.h",
-    "src/core/lib/security/credentials/ssl/ssl_credentials.h",
-    "src/core/lib/security/transport/auth_filters.h",
-    "src/core/lib/security/transport/secure_endpoint.h",
-    "src/core/lib/security/transport/security_connector.h",
-    "src/core/lib/security/transport/security_handshaker.h",
-    "src/core/lib/security/transport/tsi_error.h",
-    "src/core/lib/security/util/b64.h",
-    "src/core/lib/security/util/json_util.h",
-    "src/core/lib/tsi/fake_transport_security.h",
-    "src/core/lib/tsi/ssl_transport_security.h",
-    "src/core/lib/tsi/ssl_types.h",
-    "src/core/lib/tsi/transport_security.h",
-    "src/core/lib/tsi/transport_security_interface.h",
-    "src/core/ext/transport/chttp2/server/chttp2_server.h",
-    "src/core/ext/client_channel/client_channel.h",
-    "src/core/ext/client_channel/client_channel_factory.h",
-    "src/core/ext/client_channel/connector.h",
-    "src/core/ext/client_channel/http_connect_handshaker.h",
-    "src/core/ext/client_channel/initial_connect_string.h",
-    "src/core/ext/client_channel/lb_policy.h",
-    "src/core/ext/client_channel/lb_policy_factory.h",
-    "src/core/ext/client_channel/lb_policy_registry.h",
-    "src/core/ext/client_channel/parse_address.h",
-    "src/core/ext/client_channel/resolver.h",
-    "src/core/ext/client_channel/resolver_factory.h",
-    "src/core/ext/client_channel/resolver_registry.h",
-    "src/core/ext/client_channel/subchannel.h",
-    "src/core/ext/client_channel/subchannel_index.h",
-    "src/core/ext/client_channel/uri_parser.h",
-    "src/core/ext/transport/chttp2/client/chttp2_connector.h",
-    "src/core/ext/lb_policy/grpclb/grpclb.h",
-    "src/core/ext/lb_policy/grpclb/load_balancer_api.h",
-    "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h",
-    "src/core/ext/load_reporting/load_reporting.h",
-    "src/core/ext/load_reporting/load_reporting_filter.h",
-    "src/core/ext/census/aggregation.h",
-    "src/core/ext/census/base_resources.h",
-    "src/core/ext/census/census_interface.h",
-    "src/core/ext/census/census_rpc_stats.h",
-    "src/core/ext/census/gen/census.pb.h",
-    "src/core/ext/census/gen/trace_context.pb.h",
-    "src/core/ext/census/grpc_filter.h",
-    "src/core/ext/census/mlog.h",
-    "src/core/ext/census/resource.h",
-    "src/core/ext/census/rpc_metric_id.h",
-    "src/core/ext/census/trace_context.h",
-  ],
-  includes = [
-    "include",
-    ".",
-  ],
-  deps = [
-    ":gpr_objc",
-    "//external:libssl_objc",
-    "//external:nanopb",
-  ],
-  sdk_dylibs = ["libz"],
+grpc_cc_library(
+    name = "grpc++_codegen_base_src",
+    srcs = [
+        "src/cpp/codegen/codegen_init.cc",
+    ],
+    language = "c++",
+    deps = [
+        "grpc++_codegen_base",
+    ],
 )
 
-
-
-cc_binary(
-  name = "grpc_cpp_plugin",
-  srcs = [
-    "src/compiler/cpp_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
+grpc_cc_library(
+    name = "grpc++_codegen_proto",
+    language = "c++",
+    public_hdrs = [
+        "include/grpc++/impl/codegen/proto_utils.h",
+    ],
+    deps = [
+        "grpc++_codegen_base",
+        "grpc++_config_proto",
+    ],
 )
 
-
-cc_binary(
-  name = "grpc_csharp_plugin",
-  srcs = [
-    "src/compiler/csharp_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
+grpc_cc_library(
+    name = "grpc++_config_proto",
+    language = "c++",
+    public_hdrs = [
+        "include/grpc++/impl/codegen/config_protobuf.h",
+    ],
 )
 
-
-cc_binary(
-  name = "grpc_node_plugin",
-  srcs = [
-    "src/compiler/node_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
-)
-
-
-cc_binary(
-  name = "grpc_objective_c_plugin",
-  srcs = [
-    "src/compiler/objective_c_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
-)
-
-
-cc_binary(
-  name = "grpc_php_plugin",
-  srcs = [
-    "src/compiler/php_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
-)
-
-
-cc_binary(
-  name = "grpc_python_plugin",
-  srcs = [
-    "src/compiler/python_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
-)
-
-
-cc_binary(
-  name = "grpc_ruby_plugin",
-  srcs = [
-    "src/compiler/ruby_plugin.cc",
-  ],
-  deps = [
-    "//external:protobuf_compiler",
-    ":grpc_plugin_support",
-  ],
-)
-
-
-
-
-
-
-
-
-objc_path = "src/objective-c"
-
-rx_library_path = objc_path + "/RxLibrary"
-
-objc_library(
-  name = "rx_library",
-  hdrs = glob([
-    rx_library_path + "/*.h",
-    rx_library_path + "/transformations/*.h",
-  ]),
-  srcs = glob([
-    rx_library_path + "/*.m",
-    rx_library_path + "/transformations/*.m",
-  ]),
-  includes = [objc_path],
-  deps = [
-    ":rx_library_private",
-  ],
-)
-
-objc_library(
-  name = "rx_library_private",
-  hdrs = glob([rx_library_path + "/private/*.h"]),
-  srcs = glob([rx_library_path + "/private/*.m"]),
-  visibility = ["//visibility:private"],
-)
-
-objc_client_path = objc_path + "/GRPCClient"
-
-objc_library(
-  name = "grpc_client",
-  hdrs = glob([
-    objc_client_path + "/*.h",
-    objc_client_path + "/private/*.h",
-  ]),
-  srcs = glob([
-    objc_client_path + "/*.m",
-    objc_client_path + "/private/*.m",
-  ]),
-  includes = [objc_path],
-  bundles = [":gRPCCertificates"],
-  deps = [
-    ":grpc_objc",
-    ":rx_library",
-  ],
-)
-
-objc_bundle_library(
-    # The choice of name is signicant here, since it determines the bundle name.
-    name = "gRPCCertificates",
-    resources = ["etc/roots.pem"],
-)
-
-proto_objc_rpc_path = objc_path + "/ProtoRPC"
-
-objc_library(
-  name = "proto_objc_rpc",
-  hdrs = glob([
-    proto_objc_rpc_path + "/*.h",
-  ]),
-  srcs = glob([
-    proto_objc_rpc_path + "/*.m",
-  ]),
-  includes = [objc_path],
-  deps = [
-    ":grpc_client",
-    ":rx_library",
-    "//external:protobuf_objc",
-  ],
+grpc_cc_library(
+    name = "thrift_util",
+    language = "c++",
+    public_hdrs = [
+        "include/grpc++/impl/codegen/thrift_serializer.h",
+        "include/grpc++/impl/codegen/thrift_utils.h",
+    ],
+    deps = [
+        "grpc++_codegen_base",
+    ],
 )
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ff09275..4627c10 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,7 +66,13 @@
 set(gRPC_USE_PROTO_LITE OFF CACHE BOOL "Use the protobuf-lite library")
 
 if (MSVC)
-  add_definitions( -D_WIN32_WINNT=0x600 )
+  add_definitions(-D_WIN32_WINNT=0x600 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS)
+  # needed to compile boringssl
+  add_definitions(/wd4464 /wd4623 /wd4668 /wd4701 /wd4702 /wd4777 /wd5027)
+  # needed to compile protobuf
+  add_definitions(/wd4065 /wd4506)
+  # TODO(jtattermusch): revisit C4267 occurrences throughout the code
+  add_definitions(/wd4267)
 endif()
 
 if (gRPC_USE_PROTO_LITE)
@@ -292,6 +298,8 @@
   src/core/lib/channel/connected_channel.c
   src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
+  src/core/lib/channel/handshaker_factory.c
+  src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/channel/message_size_filter.c
@@ -530,6 +538,7 @@
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/exec_ctx_fwd.h
   include/grpc/impl/codegen/grpc_types.h
   include/grpc/impl/codegen/propagation_bits.h
   include/grpc/impl/codegen/status.h
@@ -573,6 +582,8 @@
   src/core/lib/channel/connected_channel.c
   src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
+  src/core/lib/channel/handshaker_factory.c
+  src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/channel/message_size_filter.c
@@ -781,6 +792,7 @@
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/exec_ctx_fwd.h
   include/grpc/impl/codegen/grpc_types.h
   include/grpc/impl/codegen/propagation_bits.h
   include/grpc/impl/codegen/status.h
@@ -825,6 +837,8 @@
   src/core/lib/channel/connected_channel.c
   src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
+  src/core/lib/channel/handshaker_factory.c
+  src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/channel/message_size_filter.c
@@ -1032,6 +1046,7 @@
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/exec_ctx_fwd.h
   include/grpc/impl/codegen/grpc_types.h
   include/grpc/impl/codegen/propagation_bits.h
   include/grpc/impl/codegen/status.h
@@ -1195,6 +1210,7 @@
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/exec_ctx_fwd.h
   include/grpc/impl/codegen/grpc_types.h
   include/grpc/impl/codegen/propagation_bits.h
   include/grpc/impl/codegen/status.h
@@ -1292,6 +1308,8 @@
   src/core/lib/channel/connected_channel.c
   src/core/lib/channel/deadline_filter.c
   src/core/lib/channel/handshaker.c
+  src/core/lib/channel/handshaker_factory.c
+  src/core/lib/channel/handshaker_registry.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/channel/message_size_filter.c
@@ -1528,6 +1546,7 @@
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/exec_ctx_fwd.h
   include/grpc/impl/codegen/grpc_types.h
   include/grpc/impl/codegen/propagation_bits.h
   include/grpc/impl/codegen/status.h
@@ -1570,45 +1589,6 @@
 endif()
 
   
-add_library(grpc++_reflection
-  src/cpp/ext/proto_server_reflection.cc
-  src/cpp/ext/proto_server_reflection_plugin.cc
-  src/proto/grpc/reflection/v1alpha/reflection.proto
-)
-
-target_include_directories(grpc++_reflection
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-)
-
-target_link_libraries(grpc++_reflection
-  grpc++
-)
-
-foreach(_hdr
-  include/grpc++/ext/proto_server_reflection_plugin.h
-)
-  string(REPLACE "include/" "" _path ${_hdr})
-  get_filename_component(_path ${_path} PATH)
-  install(FILES ${_hdr}
-    DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${_path}"
-  )
-endforeach()
-
-  
-if (gRPC_INSTALL)
-  install(TARGETS grpc++_reflection EXPORT gRPCTargets
-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-  )
-endif()
-
-  
 add_library(grpc++_unsecure
   src/cpp/client/insecure_credentials.cc
   src/cpp/common/insecure_create_auth_context.cc
@@ -1734,6 +1714,7 @@
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/exec_ctx_fwd.h
   include/grpc/impl/codegen/grpc_types.h
   include/grpc/impl/codegen/propagation_bits.h
   include/grpc/impl/codegen/status.h
@@ -1808,35 +1789,6 @@
   )
 endif()
 
-  
-add_library(grpc_csharp_ext
-  src/csharp/ext/grpc_csharp_ext.c
-)
-
-target_include_directories(grpc_csharp_ext
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-)
-
-target_link_libraries(grpc_csharp_ext
-  grpc
-  gpr
-)
-
-
-  
-if (gRPC_INSTALL)
-  install(TARGETS grpc_csharp_ext EXPORT gRPCTargets
-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-  )
-endif()
-
 
 
 add_executable(gen_hpack_tables
diff --git a/Makefile b/Makefile
index 8f7328a..e4cfd30 100644
--- a/Makefile
+++ b/Makefile
@@ -292,12 +292,19 @@
 endif
 STRIP ?= strip -x
 else
+ifeq ($(SYSTEM),MINGW32)
+ifeq ($(origin AR), default)
+AR = ar rcs
+endif
+STRIP ?= strip --strip-unneeded
+else
 ifeq ($(origin AR), default)
 AR = ar rcs
 endif
 STRIP ?= strip
 endif
 endif
+endif
 INSTALL ?= install
 RM ?= rm -f
 PKG_CONFIG ?= pkg-config
@@ -479,6 +486,7 @@
 CSHARP_PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(CSHARP_VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
 
 ifeq ($(SYSTEM),MINGW32)
+EXECUTABLE_SUFFIX = .exe
 SHARED_EXT_CORE = dll
 SHARED_EXT_CPP = dll
 SHARED_EXT_CSHARP = dll
@@ -487,6 +495,7 @@
 SHARED_VERSION_CPP = -1
 SHARED_VERSION_CSHARP = -1
 else ifeq ($(SYSTEM),Darwin)
+EXECUTABLE_SUFFIX = 
 SHARED_EXT_CORE = dylib
 SHARED_EXT_CPP = dylib
 SHARED_EXT_CSHARP = dylib
@@ -495,6 +504,7 @@
 SHARED_VERSION_CPP =
 SHARED_VERSION_CSHARP =
 else
+EXECUTABLE_SUFFIX = 
 SHARED_EXT_CORE = so.$(CORE_VERSION)
 SHARED_EXT_CPP = so.$(CPP_VERSION)
 SHARED_EXT_CSHARP = so.$(CSHARP_VERSION)
@@ -1013,6 +1023,9 @@
 lb_policies_test: $(BINDIR)/$(CONFIG)/lb_policies_test
 load_file_test: $(BINDIR)/$(CONFIG)/load_file_test
 low_level_ping_pong_benchmark: $(BINDIR)/$(CONFIG)/low_level_ping_pong_benchmark
+memory_profile_client: $(BINDIR)/$(CONFIG)/memory_profile_client
+memory_profile_server: $(BINDIR)/$(CONFIG)/memory_profile_server
+memory_profile_test: $(BINDIR)/$(CONFIG)/memory_profile_test
 message_compress_test: $(BINDIR)/$(CONFIG)/message_compress_test
 mlog_test: $(BINDIR)/$(CONFIG)/mlog_test
 multiple_server_queues_test: $(BINDIR)/$(CONFIG)/multiple_server_queues_test
@@ -1085,6 +1098,7 @@
 grpc_tool_test: $(BINDIR)/$(CONFIG)/grpc_tool_test
 grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test
 grpclb_test: $(BINDIR)/$(CONFIG)/grpclb_test
+http2_client: $(BINDIR)/$(CONFIG)/http2_client
 hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
 interop_client: $(BINDIR)/$(CONFIG)/interop_client
 interop_server: $(BINDIR)/$(CONFIG)/interop_server
@@ -1260,9 +1274,9 @@
 pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 ifeq ($(EMBED_OPENSSL),true)
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
 else
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_proto_reflection_desc_db.a $(LIBDIR)/$(CONFIG)/libgrpc++_test.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libbenchmark.a
 endif
 
 
@@ -1348,6 +1362,9 @@
   $(BINDIR)/$(CONFIG)/lame_client_test \
   $(BINDIR)/$(CONFIG)/lb_policies_test \
   $(BINDIR)/$(CONFIG)/load_file_test \
+  $(BINDIR)/$(CONFIG)/memory_profile_client \
+  $(BINDIR)/$(CONFIG)/memory_profile_server \
+  $(BINDIR)/$(CONFIG)/memory_profile_test \
   $(BINDIR)/$(CONFIG)/message_compress_test \
   $(BINDIR)/$(CONFIG)/mlog_test \
   $(BINDIR)/$(CONFIG)/multiple_server_queues_test \
@@ -1467,6 +1484,7 @@
   $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
   $(BINDIR)/$(CONFIG)/grpclb_test \
+  $(BINDIR)/$(CONFIG)/http2_client \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
   $(BINDIR)/$(CONFIG)/interop_client \
   $(BINDIR)/$(CONFIG)/interop_server \
@@ -1560,6 +1578,7 @@
   $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
   $(BINDIR)/$(CONFIG)/grpclb_test \
+  $(BINDIR)/$(CONFIG)/http2_client \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
   $(BINDIR)/$(CONFIG)/interop_client \
   $(BINDIR)/$(CONFIG)/interop_server \
@@ -1739,6 +1758,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/lame_client_test || ( echo test lame_client_test failed ; exit 1 )
 	$(E) "[RUN]     Testing load_file_test"
 	$(Q) $(BINDIR)/$(CONFIG)/load_file_test || ( echo test load_file_test failed ; exit 1 )
+	$(E) "[RUN]     Testing memory_profile_test"
+	$(Q) $(BINDIR)/$(CONFIG)/memory_profile_test || ( echo test memory_profile_test failed ; exit 1 )
 	$(E) "[RUN]     Testing message_compress_test"
 	$(Q) $(BINDIR)/$(CONFIG)/message_compress_test || ( echo test message_compress_test failed ; exit 1 )
 	$(E) "[RUN]     Testing multiple_server_queues_test"
@@ -2039,7 +2060,7 @@
 $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc: src/proto/grpc/lb/v1/load_balancer.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2054,7 +2075,7 @@
 $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc: src/proto/grpc/reflection/v1alpha/reflection.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2069,7 +2090,7 @@
 $(GENDIR)/src/proto/grpc/testing/compiler_test.grpc.pb.cc: src/proto/grpc/testing/compiler_test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2084,7 +2105,7 @@
 $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc: src/proto/grpc/testing/control.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2099,7 +2120,7 @@
 $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc: src/proto/grpc/testing/duplicate/echo_duplicate.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2114,7 +2135,7 @@
 $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc: src/proto/grpc/testing/echo.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2129,7 +2150,7 @@
 $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc: src/proto/grpc/testing/echo_messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2144,7 +2165,7 @@
 $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc: src/proto/grpc/testing/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2159,7 +2180,7 @@
 $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc: src/proto/grpc/testing/messages.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2174,7 +2195,7 @@
 $(GENDIR)/src/proto/grpc/testing/metrics.grpc.pb.cc: src/proto/grpc/testing/metrics.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2189,7 +2210,7 @@
 $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc: src/proto/grpc/testing/payloads.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2204,7 +2225,7 @@
 $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2219,7 +2240,7 @@
 $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc: src/proto/grpc/testing/stats.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2234,7 +2255,7 @@
 $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc: src/proto/grpc/testing/test.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
 endif
 
 
@@ -2327,36 +2348,36 @@
 install-shared_c: shared_c strip-shared_c install-pkg-config_c
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr-imp.a $(prefix)/lib/libgpr-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgpr.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgpr.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc-imp.a $(prefix)/lib/libgrpc-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_cronet-imp.a $(prefix)/lib/libgrpc_cronet-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc_cronet.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_cronet.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure-imp.a $(prefix)/lib/libgrpc_unsecure-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a $(prefix)/lib/libgrpc_unsecure.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(prefix)/lib/libgrpc_unsecure.so
@@ -2371,36 +2392,36 @@
 install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-config_cxx
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++-imp.a $(prefix)/lib/libgrpc++-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet-imp.a $(prefix)/lib/libgrpc++_cronet-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_cronet.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_cronet.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection-imp.a $(prefix)/lib/libgrpc++_reflection-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_reflection.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_reflection.so
 endif
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure-imp.a $(prefix)/lib/libgrpc++_unsecure-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a $(prefix)/lib/libgrpc++_unsecure.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(prefix)/lib/libgrpc++_unsecure.so
@@ -2415,9 +2436,9 @@
 install-shared_csharp: shared_csharp strip-shared_csharp
 	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP)
 ifeq ($(SYSTEM),MINGW32)
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext-imp.a $(prefix)/lib/libgrpc_csharp_ext-imp.a
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a $(prefix)/lib/libgrpc_csharp_ext.a
 else ifneq ($(SYSTEM),Darwin)
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so.2
 	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(prefix)/lib/libgrpc_csharp_ext.so
@@ -2430,9 +2451,6 @@
 
 
 install-plugins: $(PROTOC_PLUGINS)
-ifeq ($(SYSTEM),MINGW32)
-	$(Q) false
-else
 	$(E) "[INSTALL] Installing grpc protoc plugins"
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(prefix)/bin/grpc_cpp_plugin
@@ -2448,7 +2466,6 @@
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_python_plugin $(prefix)/bin/grpc_python_plugin
 	$(Q) $(INSTALL) -d $(prefix)/bin
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
-endif
 
 install-pkg-config_c: pc_c pc_c_unsecure
 	$(E) "[INSTALL] Installing C pkg-config files"
@@ -2578,17 +2595,17 @@
 $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared gpr.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
 else
 $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGPR_OBJS)  $(ZLIB_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.2 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.2
-	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -2631,6 +2648,8 @@
     src/core/lib/channel/connected_channel.c \
     src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/handshaker_factory.c \
+    src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/channel/message_size_filter.c \
@@ -2852,6 +2871,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -2898,17 +2918,17 @@
 $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
 $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.2
-	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -2930,6 +2950,8 @@
     src/core/lib/channel/connected_channel.c \
     src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/handshaker_factory.c \
+    src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/channel/message_size_filter.c \
@@ -3122,6 +3144,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -3168,17 +3191,17 @@
 $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_cronet.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
 $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_CRONET_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_cronet.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_CRONET_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.2
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -3219,6 +3242,8 @@
     src/core/lib/channel/connected_channel.c \
     src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/handshaker_factory.c \
+    src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/channel/message_size_filter.c \
@@ -3338,6 +3363,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -3436,6 +3462,8 @@
     src/core/lib/channel/connected_channel.c \
     src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/handshaker_factory.c \
+    src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/channel/message_size_filter.c \
@@ -3628,6 +3656,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -3662,17 +3691,17 @@
 $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
 $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
 	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.2
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so.2
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION_CORE).so
 endif
 endif
 
@@ -3872,6 +3901,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -3922,20 +3952,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc$(SHARED_VERSION_CORE)-dll
 else
 $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
 else
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -4015,6 +4045,8 @@
     src/core/lib/channel/connected_channel.c \
     src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/handshaker_factory.c \
+    src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/channel/message_size_filter.c \
@@ -4234,6 +4266,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -4294,20 +4327,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_cronet.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_cronet$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_cronet.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_cronet-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr$(SHARED_VERSION_CORE)-dll -lgrpc_cronet$(SHARED_VERSION_CORE)-dll
 else
 $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_CRONET_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.$(SHARED_EXT_CORE) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
 else
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_cronet.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_CRONET_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_cronet
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_cronet$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_cronet$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -4417,20 +4450,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_reflection.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++$(SHARED_VERSION_CPP)-dll
 else
 $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_REFLECTION_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT_CPP) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
 else
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_reflection.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_REFLECTION_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc++
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_reflection$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -4589,6 +4622,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -4767,6 +4801,7 @@
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/exec_ctx_fwd.h \
     include/grpc/impl/codegen/grpc_types.h \
     include/grpc/impl/codegen/propagation_bits.h \
     include/grpc/impl/codegen/status.h \
@@ -4807,20 +4842,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT_CORE)
+$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION_CORE).$(SHARED_EXT_CORE)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr$(SHARED_VERSION_CORE)-dll -lgrpc_unsecure$(SHARED_VERSION_CORE)-dll
 else
 $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT_CORE) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT_CORE)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 else
 	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION_CPP).$(SHARED_EXT_CPP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION_CPP).so
 endif
 endif
 
@@ -4934,6 +4969,59 @@
 endif
 
 
+LIBHTTP2_CLIENT_MAIN_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc \
+    test/cpp/interop/http2_client.cc \
+
+PUBLIC_HEADERS_CXX += \
+
+LIBHTTP2_CLIENT_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBHTTP2_CLIENT_MAIN_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libhttp2_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBHTTP2_CLIENT_MAIN_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBHTTP2_CLIENT_MAIN_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBHTTP2_CLIENT_MAIN_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/http2_client.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
+
+
 LIBINTEROP_CLIENT_HELPER_SRC = \
     $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc \
     test/cpp/interop/client_helper.cc \
@@ -5300,17 +5388,17 @@
 $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared grpc_csharp_ext.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
 $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
 	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.2 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so.1
-	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so.1
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION_CSHARP).$(SHARED_EXT_CSHARP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION_CSHARP).so
 endif
 endif
 
@@ -10272,6 +10360,102 @@
 endif
 
 
+MEMORY_PROFILE_CLIENT_SRC = \
+    test/core/memory_usage/client.c \
+
+MEMORY_PROFILE_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_CLIENT_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/memory_profile_client: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/memory_profile_client: $(MEMORY_PROFILE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_client
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/memory_usage/client.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_memory_profile_client: $(MEMORY_PROFILE_CLIENT_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(MEMORY_PROFILE_CLIENT_OBJS:.o=.dep)
+endif
+endif
+
+
+MEMORY_PROFILE_SERVER_SRC = \
+    test/core/memory_usage/server.c \
+
+MEMORY_PROFILE_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_SERVER_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/memory_profile_server: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/memory_profile_server: $(MEMORY_PROFILE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_server
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/memory_usage/server.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_memory_profile_server: $(MEMORY_PROFILE_SERVER_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(MEMORY_PROFILE_SERVER_OBJS:.o=.dep)
+endif
+endif
+
+
+MEMORY_PROFILE_TEST_SRC = \
+    test/core/memory_usage/memory_usage_test.c \
+
+MEMORY_PROFILE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(MEMORY_PROFILE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/memory_profile_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/memory_profile_test: $(MEMORY_PROFILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(MEMORY_PROFILE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/memory_profile_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/memory_usage/memory_usage_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_memory_profile_test: $(MEMORY_PROFILE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(MEMORY_PROFILE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 MESSAGE_COMPRESS_TEST_SRC = \
     test/core/compression/message_compress_test.c \
 
@@ -12888,6 +13072,37 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
 
 
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/http2_client: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/http2_client: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/http2_client:  $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libhttp2_client_main.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/http2_client
+
+endif
+
+endif
+
+
+
+
 HYBRID_END2END_TEST_SRC = \
     test/cpp/end2end/hybrid_end2end_test.cc \
 
@@ -16805,6 +17020,7 @@
 test/cpp/end2end/test_service_impl.cc: $(OPENSSL_DEP)
 test/cpp/interop/client.cc: $(OPENSSL_DEP)
 test/cpp/interop/client_helper.cc: $(OPENSSL_DEP)
+test/cpp/interop/http2_client.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_client.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_server.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_server_bootstrap.cc: $(OPENSSL_DEP)
diff --git a/README.md b/README.md
index 70cf9fc..174e861 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@
 
 See [tools/run_tests](tools/run_tests) for more guidance on how to run various test suites (e.g. unit tests, interop tests, benchmarks)
 
+See [Performance dashboard](http://performance-dot-grpc-testing.appspot.com/explore?dashboard=5712453606309888) for the performance numbers for v1.0.x.
+
 #Repository Structure & Status
 
 This repository contains source code for gRPC libraries for multiple languages written on top of shared C core library [src/core] (src/core).
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..9883109
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,47 @@
+bind(
+    name = "nanopb",
+    actual = "//third_party/nanopb",
+)
+
+bind(
+    name = "libssl",
+    actual = "@submodule_boringssl//:ssl",
+)
+
+bind(
+    name = "zlib",
+    actual = "@submodule_zlib//:z",
+)
+
+bind(
+    name = "protobuf",
+    actual = "@submodule_protobuf//:protobuf",
+)
+
+bind(
+    name = "protobuf_clib",
+    actual = "@submodule_protobuf//:protoc_lib",
+)
+
+bind(
+    name = "protocol_compiler",
+    actual = "@submodule_protobuf//:protoc",
+)
+
+new_local_repository(
+    name = "submodule_boringssl",
+    path = "third_party/boringssl-with-bazel",
+    build_file = "third_party/boringssl-with-bazel/BUILD",
+)
+
+new_local_repository(
+    name = "submodule_zlib",
+    path = "third_party/zlib",
+    build_file = "third_party/zlib.BUILD",
+)
+
+new_local_repository(
+    name = "submodule_protobuf",
+    path = "third_party/protobuf",
+    build_file = "third_party/protobuf/BUILD",
+)
diff --git a/bazel/BUILD b/bazel/BUILD
new file mode 100644
index 0000000..940a379
--- /dev/null
+++ b/bazel/BUILD
@@ -0,0 +1,9 @@
+package(default_visibility = ["//:__subpackages__"])
+
+load(":cc_grpc_library.bzl", "cc_grpc_library")
+
+cc_grpc_library(
+    name = "well_known_protos",
+    srcs = "@submodule_protobuf//:well_known_protos",
+    proto_only = True,
+)
diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl
new file mode 100644
index 0000000..e1dd27b
--- /dev/null
+++ b/bazel/cc_grpc_library.bzl
@@ -0,0 +1,62 @@
+"""Generates and compiles C++ grpc stubs from proto_library rules."""
+
+load("//:bazel/generate_cc.bzl", "generate_cc")
+
+def cc_grpc_library(name, srcs, deps, proto_only, **kwargs):
+  """Generates C++ grpc classes from a .proto file.
+
+  Assumes the generated classes will be used in cc_api_version = 2.
+
+  Arguments:
+      name: name of rule.
+      srcs: a single proto_library, which wraps the .proto files with services.
+      deps: a list of C++ proto_library (or cc_proto_library) which provides
+        the compiled code of any message that the services depend on.
+      **kwargs: rest of arguments, e.g., compatible_with and visibility.
+  """
+  if len(srcs) > 1:
+    fail("Only one srcs value supported", "srcs")
+
+  proto_target = "_" + name + "_only"
+  codegen_target = "_" + name + "_codegen"
+  codegen_grpc_target = "_" + name + "_grpc_codegen"
+  proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(':') == -1]
+  proto_deps += [dep.split(':')[0] + ':' + "_" + dep.split(':')[1] + "_only" for dep in deps if dep.find(':') != -1]
+
+  native.proto_library(
+      name = proto_target,
+      srcs = srcs,
+      deps = proto_deps,
+      **kwargs
+  )
+
+  generate_cc(
+      name = codegen_target,
+      srcs = [proto_target],
+      **kwargs
+  )
+
+  if not proto_only:
+    generate_cc(
+        name = codegen_grpc_target,
+        srcs = [proto_target],
+        plugin = "//:grpc_cpp_plugin",
+        **kwargs
+    )
+
+  if not proto_only:
+    native.cc_library(
+        name = name,
+        srcs = [":" + codegen_grpc_target, ":" + codegen_target],
+        hdrs = [":" + codegen_grpc_target, ":" + codegen_target],
+        deps = deps + ["//:grpc++", "//:grpc++_codegen_proto", "//external:protobuf"],
+        **kwargs
+    )
+  else:
+    native.cc_library(
+        name = name,
+        srcs = [":" + codegen_target],
+        hdrs = [":" + codegen_target],
+        deps = deps + ["//external:protobuf"],
+        **kwargs
+    )
diff --git a/bazel/generate_cc.bzl b/bazel/generate_cc.bzl
new file mode 100644
index 0000000..3665733
--- /dev/null
+++ b/bazel/generate_cc.bzl
@@ -0,0 +1,66 @@
+"""Generates C++ grpc stubs from proto_library rules.
+
+This is an internal rule used by cc_grpc_library, and shouldn't be used
+directly.
+"""
+
+def generate_cc_impl(ctx):
+  """Implementation of the generate_cc rule."""
+  protos = [f for src in ctx.attr.srcs for f in src.proto.direct_sources]
+  includes = [f for src in ctx.attr.srcs for f in src.proto.transitive_imports]
+  outs = []
+  if ctx.executable.plugin:
+    outs += [proto.basename[:-len(".proto")] + ".grpc.pb.h" for proto in protos]
+    outs += [proto.basename[:-len(".proto")] + ".grpc.pb.cc" for proto in protos]
+  else:
+    outs += [proto.basename[:-len(".proto")] + ".pb.h" for proto in protos]
+    outs += [proto.basename[:-len(".proto")] + ".pb.cc" for proto in protos]
+  out_files = [ctx.new_file(out) for out in outs]
+  # The following should be replaced with ctx.configuration.buildout
+  # whenever this is added to Skylark.
+  dir_out = out_files[0].dirname[:-len(protos[0].dirname)]
+
+  arguments = []
+  if ctx.executable.plugin:
+    arguments += ["--plugin=protoc-gen-PLUGIN=" + ctx.executable.plugin.path]
+    arguments += ["--PLUGIN_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
+  else:
+    arguments += ["--cpp_out=" + ",".join(ctx.attr.flags) + ":" + dir_out]
+  arguments += ["-I{0}={0}".format(include.path) for include in includes]
+  arguments += [proto.path for proto in protos]
+
+  ctx.action(
+      inputs = protos + includes,
+      outputs = out_files,
+      executable = ctx.executable._protoc,
+      arguments = arguments,
+  )
+
+  return struct(files=set(out_files))
+
+generate_cc = rule(
+    attrs = {
+        "srcs": attr.label_list(
+            mandatory = True,
+            non_empty = True,
+            providers = ["proto"],
+        ),
+        "plugin": attr.label(
+            executable = True,
+            providers = ["files_to_run"],
+            cfg = "host",
+        ),
+        "flags": attr.string_list(
+            mandatory = False,
+            allow_empty = True,
+        ),
+        "_protoc": attr.label(
+            default = Label("//external:protocol_compiler"),
+            executable = True,
+            cfg = "host",
+        ),
+    },
+    # We generate .h files, so we need to output to genfiles.
+    output_to_genfiles = True,
+    implementation = generate_cc_impl,
+)
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
new file mode 100644
index 0000000..daf8b78
--- /dev/null
+++ b/bazel/grpc_build_system.bzl
@@ -0,0 +1,68 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# This is for the gRPC build system. This isn't intended to be used outsite of
+# the BUILD file for gRPC. It contains the mapping for the template system we
+# use to generate other platform's build system files.
+#
+
+def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language = "C++"):
+  copts = []
+  if language.upper() == "C":
+    copts = ["-std=c99"]
+  native.cc_library(
+    name = name,
+    srcs = srcs,
+    hdrs = hdrs + public_hdrs,
+    deps = deps + ["//external:" + dep for dep in external_deps],
+    copts = copts,
+    linkopts = ["-pthread"],
+    includes = [
+        "include"
+    ]
+  )
+
+def grpc_proto_plugin(name, srcs = [], deps = []):
+  native.cc_binary(
+    name = name,
+    srcs = srcs,
+    deps = deps,
+  )
+
+load("//:bazel/cc_grpc_library.bzl", "cc_grpc_library")
+
+def grpc_proto_library(name, srcs = [], deps = [], well_known_deps = [], has_services = True):
+  cc_grpc_library(
+    name = name,
+    srcs = srcs,
+    deps = deps,
+    proto_only = not has_services,
+  )
+
diff --git a/binding.gyp b/binding.gyp
index 516cbdc..479403e 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -37,18 +37,68 @@
 # Some of this file is built with the help of
 # https://n8.io/converting-a-c-library-to-gyp/
 {
+  'variables': {
+    'runtime%': 'node'
+  },
   'target_defaults': {
     'include_dirs': [
       '.',
       'include'
     ],
     'defines': [
-      'GRPC_UV'
+      'GPR_BACKWARDS_COMPATIBILITY_MODE'
     ],
     'conditions': [
+      ['runtime=="node"', {
+        'defines': [
+          'GRPC_UV'
+        ]
+      }],
+      ['OS!="win" and runtime=="electron"', {
+        "defines": [
+          'OPENSSL_NO_THREADS'
+        ]
+      }],
+      # This is the condition for using boringssl
+      ['OS=="win" or runtime=="electron"', {
+        "include_dirs": [
+          "third_party/boringssl/include"
+        ],
+        "defines": [
+          'OPENSSL_NO_ASM'
+        ]
+      }, {
+        # Based on logic above, we know that this must be a non-Windows system
+        'variables': {
+          # The output of "node --version" is "v[version]". We use cut to
+          # remove the first character.
+          'target%': '<!(node --version | cut -c2-)'
+        },
+        # Empirically, Node only exports ALPN symbols if its major version is >0.
+        # io.js always reports versions >0 and always exports ALPN symbols.
+        # Therefore, Node's major version will be truthy if and only if it
+        # supports ALPN. The target is "[major].[minor].[patch]". We split by
+        # periods and take the first field to get the major version.
+        'defines': [
+          'TSI_OPENSSL_ALPN_SUPPORT=<!(echo <(target) | cut -d. -f1)'
+        ],
+        'include_dirs': [
+          '<(node_root_dir)/deps/openssl/openssl/include',
+        ],
+        'conditions': [
+         ["target_arch=='ia32'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
+         }],
+         ["target_arch=='x64'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
+         }],
+         ["target_arch=='arm'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
+         }]
+        ]
+      }],
       ['OS == "win"', {
         "include_dirs": [
-          "third_party/boringssl/include",
           "third_party/zlib"
         ],
         "defines": [
@@ -58,8 +108,6 @@
           'UNICODE',
           '_UNICODE',
           'NOMINMAX',
-          'OPENSSL_NO_ASM',
-          'GPR_BACKWARDS_COMPATIBILITY_MODE'
         ],
         "msvs_settings": {
           'VCCLCompilerTool': {
@@ -72,21 +120,8 @@
       }, { # OS != "win"
         'variables': {
           'config': '<!(echo $CONFIG)',
-          # The output of "node --version" is "v[version]". We use cut to
-          # remove the first character.
-          'target%': '<!(node --version | cut -c2-)'
         },
-          # Empirically, Node only exports ALPN symbols if its major version is >0.
-          # io.js always reports versions >0 and always exports ALPN symbols.
-          # Therefore, Node's major version will be truthy if and only if it
-          # supports ALPN. The target is "[major].[minor].[patch]". We split by
-          # periods and take the first field to get the major version.
-        'defines': [
-          'TSI_OPENSSL_ALPN_SUPPORT=<!(echo <(target) | cut -d. -f1)',
-          'GPR_BACKWARDS_COMPATIBILITY_MODE'
-        ],
         'include_dirs': [
-          '<(node_root_dir)/deps/openssl/openssl/include',
           '<(node_root_dir)/deps/zlib'
         ],
         'conditions': [
@@ -101,48 +136,15 @@
               '-fprofile-arcs'
             ]
           }
-         ],
-         ["target_arch=='ia32'", {
-             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
-         }],
-         ["target_arch=='x64'", {
-             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
-         }],
-         ["target_arch=='arm'", {
-             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
-         }]
+         ]
         ]
       }]
     ]
   },
   'conditions': [
-    ['OS == "win"', {
+    ['OS=="win" or runtime=="electron"', {
       'targets': [
         {
-          # IMPORTANT WINDOWS BUILD INFORMATION
-          # This library does not build on Windows without modifying the Node
-          # development packages that node-gyp downloads in order to build.
-          # Due to https://github.com/nodejs/node/issues/4932, the headers for
-          # BoringSSL conflict with the OpenSSL headers included by default
-          # when including the Node headers. The remedy for this is to remove
-          # the OpenSSL headers, from the downloaded Node development package,
-          # which is typically located in `.node-gyp` in your home directory.
-          'target_name': 'WINDOWS_BUILD_WARNING',
-          'actions': [
-            {
-              'action_name': 'WINDOWS_BUILD_WARNING',
-              'inputs': [
-                'package.json'
-              ],
-              'outputs': [
-                'ignore_this_part'
-              ],
-              'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/']
-            }
-          ]
-        },
-        # Only want to compile BoringSSL and zlib under Windows
-        {
           'cflags': [
             '-std=c99',
             '-Wall',
@@ -453,6 +455,34 @@
             'third_party/boringssl/ssl/tls_record.c',
           ]
         },
+      ]
+    }],
+    ['OS == "win"', {
+      'targets': [
+        {
+          # IMPORTANT WINDOWS BUILD INFORMATION
+          # This library does not build on Windows without modifying the Node
+          # development packages that node-gyp downloads in order to build.
+          # Due to https://github.com/nodejs/node/issues/4932, the headers for
+          # BoringSSL conflict with the OpenSSL headers included by default
+          # when including the Node headers. The remedy for this is to remove
+          # the OpenSSL headers, from the downloaded Node development package,
+          # which is typically located in `.node-gyp` in your home directory.
+          'target_name': 'WINDOWS_BUILD_WARNING',
+          'actions': [
+            {
+              'action_name': 'WINDOWS_BUILD_WARNING',
+              'inputs': [
+                'package.json'
+              ],
+              'outputs': [
+                'ignore_this_part'
+              ],
+              'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/']
+            }
+          ]
+        },
+        # Only want to compile zlib under Windows
         {
           'cflags': [
             '-std=c99',
@@ -572,6 +602,8 @@
         'src/core/lib/channel/connected_channel.c',
         'src/core/lib/channel/deadline_filter.c',
         'src/core/lib/channel/handshaker.c',
+        'src/core/lib/channel/handshaker_factory.c',
+        'src/core/lib/channel/handshaker_registry.c',
         'src/core/lib/channel/http_client_filter.c',
         'src/core/lib/channel/http_server_filter.c',
         'src/core/lib/channel/message_size_filter.c',
@@ -805,6 +837,11 @@
         '-g'
       ],
       "conditions": [
+        ['OS=="win" or runtime=="electron"', {
+          'dependencies': [
+            "boringssl",
+          ]
+        }],
         ['OS=="mac"', {
           'xcode_settings': {
             'MACOSX_DEPLOYMENT_TARGET': '10.9',
@@ -816,7 +853,6 @@
         }],
         ['OS=="win"', {
           'dependencies': [
-            "boringssl",
             "z",
           ]
         }],
@@ -833,8 +869,8 @@
         "src/node/ext/call_credentials.cc",
         "src/node/ext/channel.cc",
         "src/node/ext/channel_credentials.cc",
-        "src/node/ext/completion_queue.cc",
-        "src/node/ext/completion_queue_async_worker.cc",
+        "src/node/ext/completion_queue_threadpool.cc",
+        "src/node/ext/completion_queue_uv.cc",
         "src/node/ext/node_grpc.cc",
         "src/node/ext/server.cc",
         "src/node/ext/server_credentials.cc",
diff --git a/build.yaml b/build.yaml
index de9d253..afb5b14 100644
--- a/build.yaml
+++ b/build.yaml
@@ -171,6 +171,8 @@
   - src/core/lib/channel/context.h
   - src/core/lib/channel/deadline_filter.h
   - src/core/lib/channel/handshaker.h
+  - src/core/lib/channel/handshaker_factory.h
+  - src/core/lib/channel/handshaker_registry.h
   - src/core/lib/channel/http_client_filter.h
   - src/core/lib/channel/http_server_filter.h
   - src/core/lib/channel/message_size_filter.h
@@ -237,6 +239,7 @@
   - src/core/lib/json/json_reader.h
   - src/core/lib/json/json_writer.h
   - src/core/lib/slice/percent_encoding.h
+  - src/core/lib/slice/slice_internal.h
   - src/core/lib/slice/slice_string_helpers.h
   - src/core/lib/surface/api_trace.h
   - src/core/lib/surface/call.h
@@ -268,6 +271,8 @@
   - src/core/lib/channel/connected_channel.c
   - src/core/lib/channel/deadline_filter.c
   - src/core/lib/channel/handshaker.c
+  - src/core/lib/channel/handshaker_factory.c
+  - src/core/lib/channel/handshaker_registry.c
   - src/core/lib/channel/http_client_filter.c
   - src/core/lib/channel/http_server_filter.c
   - src/core/lib/channel/message_size_filter.c
@@ -421,6 +426,7 @@
   - include/grpc/impl/codegen/byte_buffer_reader.h
   - include/grpc/impl/codegen/compression_types.h
   - include/grpc/impl/codegen/connectivity_state.h
+  - include/grpc/impl/codegen/exec_ctx_fwd.h
   - include/grpc/impl/codegen/grpc_types.h
   - include/grpc/impl/codegen/propagation_bits.h
   - include/grpc/impl/codegen/status.h
@@ -1211,6 +1217,22 @@
   vs_project_guid: '{B6E81D84-2ACB-41B8-8781-493A944C7817}'
   vs_props:
   - protoc
+- name: http2_client_main
+  build: private
+  language: c++
+  headers:
+  - test/cpp/interop/http2_client.h
+  src:
+  - src/proto/grpc/testing/empty.proto
+  - src/proto/grpc/testing/messages.proto
+  - src/proto/grpc/testing/test.proto
+  - test/cpp/interop/http2_client.cc
+  deps:
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - grpc++_test_config
 - name: interop_client_helper
   build: private
   language: c++
@@ -1253,6 +1275,7 @@
   src:
   - test/cpp/interop/server_helper.cc
   deps:
+  - grpc++_test_util
   - grpc_test_util
   - grpc++
   - grpc
@@ -2316,6 +2339,43 @@
   - mac
   - linux
   - posix
+- name: memory_profile_client
+  build: test
+  run: false
+  language: c
+  src:
+  - test/core/memory_usage/client.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+- name: memory_profile_server
+  build: test
+  run: false
+  language: c
+  src:
+  - test/core/memory_usage/server.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+- name: memory_profile_test
+  cpu_cost: 1.5
+  build: test
+  language: c
+  src:
+  - test/core/memory_usage/memory_usage_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
+  platforms:
+  - mac
+  - linux
+  - posix
 - name: message_compress_test
   build: test
   language: c
@@ -3185,6 +3245,22 @@
   - grpc++
   - grpc++_test_util
   - grpc_test_util
+- name: http2_client
+  build: test
+  run: false
+  language: c++
+  src: []
+  deps:
+  - http2_client_main
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - grpc++_test_config
+  platforms:
+  - mac
+  - linux
+  - posix
 - name: hybrid_end2end_test
   gtest: true
   build: test
@@ -3812,7 +3888,6 @@
   - src/node/ext/channel.h
   - src/node/ext/channel_credentials.h
   - src/node/ext/completion_queue.h
-  - src/node/ext/completion_queue_async_worker.h
   - src/node/ext/server.h
   - src/node/ext/server_credentials.h
   - src/node/ext/timeval.h
@@ -3831,8 +3906,8 @@
   - src/node/ext/call_credentials.cc
   - src/node/ext/channel.cc
   - src/node/ext/channel_credentials.cc
-  - src/node/ext/completion_queue.cc
-  - src/node/ext/completion_queue_async_worker.cc
+  - src/node/ext/completion_queue_threadpool.cc
+  - src/node/ext/completion_queue_uv.cc
   - src/node/ext/node_grpc.cc
   - src/node/ext/server.cc
   - src/node/ext/server_credentials.cc
diff --git a/config.m4 b/config.m4
index 4b86e25..85549e5 100644
--- a/config.m4
+++ b/config.m4
@@ -5,9 +5,9 @@
   dnl Write more examples of tests here...
 
   dnl # --with-grpc -> add include path
-  PHP_ADD_INCLUDE(../../grpc/include)
-  PHP_ADD_INCLUDE(../../grpc/src/php/ext/grpc)
-  PHP_ADD_INCLUDE(../../grpc/third_party/boringssl/include)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
 
   LIBS="-lpthread $LIBS"
 
@@ -88,6 +88,8 @@
     src/core/lib/channel/connected_channel.c \
     src/core/lib/channel/deadline_filter.c \
     src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/handshaker_factory.c \
+    src/core/lib/channel/handshaker_registry.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/channel/message_size_filter.c \
diff --git a/doc/cpp/perf_notes.md b/doc/cpp/perf_notes.md
new file mode 100644
index 0000000..c875575
--- /dev/null
+++ b/doc/cpp/perf_notes.md
@@ -0,0 +1,29 @@
+# C++ Performance Notes
+
+## Streaming write buffering
+
+Generally, each write operation (Write(), WritesDone()) implies a syscall.
+gRPC will try to batch together separate write operations from different
+threads, but currently cannot automatically infer batching in a single stream.
+
+If message k+1 in a stream does not rely on responses from message k, it's
+possible to enable write batching by passing a WriteOptions argument to Write
+with the buffer_hint set:
+
+~~~{.cpp}
+stream_writer->Write(message, WriteOptions().set_buffer_hint());
+~~~
+
+The write will be buffered until one of the following is true:
+- the per-stream buffer is filled (controllable with the channel argument
+  GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE) - this prevents infinite buffering leading
+  to OOM
+- a subsequent Write without buffer_hint set is posted
+- the call is finished for writing (WritesDone() called on the client,
+  or Finish() called on an async server stream, or the service handler returns
+  for a sync server stream)
+
+## Completion Queues and Threading in the Async API
+
+Right now, the best performance trade-off is having numcpu's threads and one
+completion queue per thread.
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 96d1f2b..da3b976 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -716,7 +716,9 @@
 
     ```
     {
-      response_size: 314159
+      response_parameters:{
+        size: 314159
+      }
       payload:{
         body: 271828 bytes of zeros
       }
diff --git a/doc/negative-http2-interop-test-descriptions.md b/doc/negative-http2-interop-test-descriptions.md
new file mode 100644
index 0000000..b64fe6a
--- /dev/null
+++ b/doc/negative-http2-interop-test-descriptions.md
@@ -0,0 +1,195 @@
+Negative HTTP/2 Interop Test Case Descriptions
+=======================================
+
+Client and server use
+[test.proto](../src/proto/grpc/testing/test.proto).
+
+Server
+------
+The code for the custom http2 server can be found
+[here](https://github.com/grpc/grpc/tree/master/test/http2_test).
+It is responsible for handling requests and sending responses, and also for 
+fulfilling the behavior of each particular test case.
+
+Server should accept these arguments:
+* --port=PORT
+  * The port the server will run on. For example, "8080"
+* --test_case=TESTCASE
+  * The name of the test case to execute. For example, "goaway"
+
+Client
+------
+
+Clients implement test cases that test certain functionality. Each client is
+provided the test case it is expected to run as a command-line parameter. Names
+should be lowercase and without spaces.
+
+Clients should accept these arguments:
+* --server_host=HOSTNAME
+    * The server host to connect to. For example, "localhost" or "127.0.0.1"
+* --server_port=PORT
+    * The server port to connect to. For example, "8080"
+* --test_case=TESTCASE
+    * The name of the test case to execute. For example, "goaway"
+
+Note
+-----
+
+Note that the server and client must be invoked with the same test case or else
+the test will be meaningless. For convenience, we provide a shell script wrapper
+that invokes both server and client at the same time, with the same test_case.
+This is the preferred way to run these tests.
+
+## Test Cases
+
+### goaway
+
+This test verifies that the client correctly responds to a goaway sent by the
+server. The client should handle the goaway by switching to a new stream without
+the user application having to do a thing.
+
+Client Procedure:
+ 1. Client sends two UnaryCall requests (and sleeps for 1 second in-between).
+ TODO: resolve [9300](https://github.com/grpc/grpc/issues/9300) and remove the 1 second sleep
+ 
+    ```
+    {
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Client asserts:
+* Both calls are successful.
+* Response payload body is 314159 bytes in size.
+
+Server Procedure:
+  1. Server sends a GOAWAY after receiving the first UnaryCall.
+
+Server asserts:
+* Two different connections were used from the client.
+
+### rst_after_header
+
+This test verifies that the client fails correctly when the server sends a
+RST_STREAM immediately after sending headers to the client.
+
+Procedure:
+ 1. Client sends UnaryCall with:
+ 
+    ```
+    {
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Client asserts:
+* Call was not successful.
+
+Server Procedure:
+  1. Server sends a RST_STREAM with error code 0 after sending headers to the client.
+  
+*At the moment the error code and message returned are not standardized throughout all
+languages. Those checks will be added once all client languages behave the same way. [#9142](https://github.com/grpc/grpc/issues/9142) is in flight.*
+
+### rst_during_data
+
+This test verifies that the client fails "correctly" when the server sends a
+RST_STREAM halfway through sending data to the client.
+
+Procedure:
+ 1. Client sends UnaryCall with:
+ 
+    ```
+    {
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Client asserts:
+* Call was not successful.
+
+Server Procedure:
+  1. Server sends a RST_STREAM with error code 0 after sending half of 
+     the requested data to the client.
+
+### rst_after_data
+
+This test verifies that the client fails "correctly" when the server sends a
+RST_STREAM after sending all of the data to the client.
+
+Procedure:
+ 1. Client sends UnaryCall with:
+ 
+    ```
+    {
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+
+Client asserts:
+* Call was not successful.
+
+Server Procedure:
+  1. Server sends a RST_STREAM with error code 0 after sending all of the
+  data to the client.
+
+*Certain client languages allow the data to be accessed even though a RST_STREAM
+was encountered. Once all client languages behave this way, checks will be added on
+the incoming data.*
+
+### ping
+
+This test verifies that the client correctly acknowledges all pings it gets from the
+server.
+
+Procedure:
+ 1. Client sends UnaryCall with:
+ 
+    ```
+    {
+      response_size: 314159
+      payload:{
+        body: 271828 bytes of zeros
+      }
+    }
+    ```
+  
+Client asserts:
+* call was successful.
+* response payload body is 314159 bytes in size.
+
+Server Procedure:
+  1. Server tracks the number of outstanding pings (i.e. +1 when it sends a ping, and -1 
+  when it receives an ack from the client).
+  2. Server sends pings before and after sending headers, also before and after sending data.
+  
+Server Asserts:
+* Number of outstanding pings is 0 when the connection is lost.
+
+### max_streams
+
+This test verifies that the client observes the MAX_CONCURRENT_STREAMS limit set by the server.
+
+Client Procedure:
+  1. Client sends initial UnaryCall to allow the server to update its MAX_CONCURRENT_STREAMS settings.
+  2. Client concurrently sends 10 UnaryCalls.
+  
+Client Asserts:
+* All UnaryCalls were successful, and had the correct type and payload size.
+ 
+Server Procedure:
+  1. Sets MAX_CONCURRENT_STREAMS to one after the connection is made.
+
+*The assertion that the MAX_CONCURRENT_STREAMS limit is upheld occurs in the http2 library we used.*
diff --git a/examples/cpp/helloworld/greeter_client.cc b/examples/cpp/helloworld/greeter_client.cc
index 12209f3..61f3953 100644
--- a/examples/cpp/helloworld/greeter_client.cc
+++ b/examples/cpp/helloworld/greeter_client.cc
@@ -51,7 +51,7 @@
   GreeterClient(std::shared_ptr<Channel> channel)
       : stub_(Greeter::NewStub(channel)) {}
 
-  // Assambles the client's payload, sends it and presents the response back
+  // Assembles the client's payload, sends it and presents the response back
   // from the server.
   std::string SayHello(const std::string& user) {
     // Data we are sending to the server.
diff --git a/examples/python/helloworld/greeter_client.py b/examples/python/helloworld/greeter_client.py
index 44d42c1..281a68f 100644
--- a/examples/python/helloworld/greeter_client.py
+++ b/examples/python/helloworld/greeter_client.py
@@ -34,11 +34,12 @@
 import grpc
 
 import helloworld_pb2
+import helloworld_pb2_grpc
 
 
 def run():
   channel = grpc.insecure_channel('localhost:50051')
-  stub = helloworld_pb2.GreeterStub(channel)
+  stub = helloworld_pb2_grpc.GreeterStub(channel)
   response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
   print("Greeter client received: " + response.message)
 
diff --git a/examples/python/helloworld/greeter_server.py b/examples/python/helloworld/greeter_server.py
index 37d8bd4..0afc21d 100644
--- a/examples/python/helloworld/greeter_server.py
+++ b/examples/python/helloworld/greeter_server.py
@@ -35,11 +35,12 @@
 import grpc
 
 import helloworld_pb2
+import helloworld_pb2_grpc
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
 
-class Greeter(helloworld_pb2.GreeterServicer):
+class Greeter(helloworld_pb2_grpc.GreeterServicer):
 
   def SayHello(self, request, context):
     return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
@@ -47,7 +48,7 @@
 
 def serve():
   server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
-  helloworld_pb2.add_GreeterServicer_to_server(Greeter(), server)
+  helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
   server.add_insecure_port('[::]:50051')
   server.start()
   try:
diff --git a/examples/python/helloworld/helloworld_pb2.py b/examples/python/helloworld/helloworld_pb2.py
index 3ce33fb..6665b1f 100644
--- a/examples/python/helloworld/helloworld_pb2.py
+++ b/examples/python/helloworld/helloworld_pb2.py
@@ -107,98 +107,123 @@
 
 DESCRIPTOR.has_options = True
 DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
-import grpc
-from grpc.beta import implementations as beta_implementations
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.common import cardinality
-from grpc.framework.interfaces.face import utilities as face_utilities
+try:
+  # THESE ELEMENTS WILL BE DEPRECATED.
+  # Please use the generated *_pb2_grpc.py files instead.
+  import grpc
+  from grpc.framework.common import cardinality
+  from grpc.framework.interfaces.face import utilities as face_utilities
+  from grpc.beta import implementations as beta_implementations
+  from grpc.beta import interfaces as beta_interfaces
 
 
-class GreeterStub(object):
-  """The greeting service definition.
-  """
-
-  def __init__(self, channel):
-    """Constructor.
-
-    Args:
-      channel: A grpc.Channel.
+  class GreeterStub(object):
+    """The greeting service definition.
     """
-    self.SayHello = channel.unary_unary(
-        '/helloworld.Greeter/SayHello',
-        request_serializer=HelloRequest.SerializeToString,
-        response_deserializer=HelloReply.FromString,
-        )
+
+    def __init__(self, channel):
+      """Constructor.
+
+      Args:
+        channel: A grpc.Channel.
+      """
+      self.SayHello = channel.unary_unary(
+          '/helloworld.Greeter/SayHello',
+          request_serializer=HelloRequest.SerializeToString,
+          response_deserializer=HelloReply.FromString,
+          )
 
 
-class GreeterServicer(object):
-  """The greeting service definition.
-  """
-
-  def SayHello(self, request, context):
-    """Sends a greeting
+  class GreeterServicer(object):
+    """The greeting service definition.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+
+    def SayHello(self, request, context):
+      """Sends a greeting
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
 
 
-def add_GreeterServicer_to_server(servicer, server):
-  rpc_method_handlers = {
-      'SayHello': grpc.unary_unary_rpc_method_handler(
-          servicer.SayHello,
-          request_deserializer=HelloRequest.FromString,
-          response_serializer=HelloReply.SerializeToString,
-      ),
-  }
-  generic_handler = grpc.method_handlers_generic_handler(
-      'helloworld.Greeter', rpc_method_handlers)
-  server.add_generic_rpc_handlers((generic_handler,))
+  def add_GreeterServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+        'SayHello': grpc.unary_unary_rpc_method_handler(
+            servicer.SayHello,
+            request_deserializer=HelloRequest.FromString,
+            response_serializer=HelloReply.SerializeToString,
+        ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+        'helloworld.Greeter', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
 
 
-class BetaGreeterServicer(object):
-  """The greeting service definition.
-  """
-  def SayHello(self, request, context):
-    """Sends a greeting
+  class BetaGreeterServicer(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """The greeting service definition.
     """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def SayHello(self, request, context):
+      """Sends a greeting
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
 
 
-class BetaGreeterStub(object):
-  """The greeting service definition.
-  """
-  def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
-    """Sends a greeting
+  class BetaGreeterStub(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """The greeting service definition.
     """
-    raise NotImplementedError()
-  SayHello.future = None
+    def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """Sends a greeting
+      """
+      raise NotImplementedError()
+    SayHello.future = None
 
 
-def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
-  request_deserializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloRequest.FromString,
-  }
-  response_serializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString,
-  }
-  method_implementations = {
-    ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
-  }
-  server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
-  return beta_implementations.server(method_implementations, options=server_options)
+  def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_deserializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloRequest.FromString,
+    }
+    response_serializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString,
+    }
+    method_implementations = {
+      ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
+    }
+    server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
+    return beta_implementations.server(method_implementations, options=server_options)
 
 
-def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
-  request_serializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString,
-  }
-  response_deserializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloReply.FromString,
-  }
-  cardinalities = {
-    'SayHello': cardinality.Cardinality.UNARY_UNARY,
-  }
-  stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
-  return beta_implementations.dynamic_stub(channel, 'helloworld.Greeter', cardinalities, options=stub_options)
+  def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_serializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString,
+    }
+    response_deserializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloReply.FromString,
+    }
+    cardinalities = {
+      'SayHello': cardinality.Cardinality.UNARY_UNARY,
+    }
+    stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
+    return beta_implementations.dynamic_stub(channel, 'helloworld.Greeter', cardinalities, options=stub_options)
+except ImportError:
+  pass
 # @@protoc_insertion_point(module_scope)
diff --git a/examples/python/helloworld/helloworld_pb2_grpc.py b/examples/python/helloworld/helloworld_pb2_grpc.py
new file mode 100644
index 0000000..682dc36
--- /dev/null
+++ b/examples/python/helloworld/helloworld_pb2_grpc.py
@@ -0,0 +1,47 @@
+import grpc
+from grpc.framework.common import cardinality
+from grpc.framework.interfaces.face import utilities as face_utilities
+
+import helloworld_pb2 as helloworld__pb2
+
+
+class GreeterStub(object):
+  """The greeting service definition.
+  """
+
+  def __init__(self, channel):
+    """Constructor.
+
+    Args:
+      channel: A grpc.Channel.
+    """
+    self.SayHello = channel.unary_unary(
+        '/helloworld.Greeter/SayHello',
+        request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
+        response_deserializer=helloworld__pb2.HelloReply.FromString,
+        )
+
+
+class GreeterServicer(object):
+  """The greeting service definition.
+  """
+
+  def SayHello(self, request, context):
+    """Sends a greeting
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+
+def add_GreeterServicer_to_server(servicer, server):
+  rpc_method_handlers = {
+      'SayHello': grpc.unary_unary_rpc_method_handler(
+          servicer.SayHello,
+          request_deserializer=helloworld__pb2.HelloRequest.FromString,
+          response_serializer=helloworld__pb2.HelloReply.SerializeToString,
+      ),
+  }
+  generic_handler = grpc.method_handlers_generic_handler(
+      'helloworld.Greeter', rpc_method_handlers)
+  server.add_generic_rpc_handlers((generic_handler,))
diff --git a/examples/python/multiplex/helloworld_pb2.py b/examples/python/multiplex/helloworld_pb2.py
index 3ce33fb..6665b1f 100644
--- a/examples/python/multiplex/helloworld_pb2.py
+++ b/examples/python/multiplex/helloworld_pb2.py
@@ -107,98 +107,123 @@
 
 DESCRIPTOR.has_options = True
 DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'))
-import grpc
-from grpc.beta import implementations as beta_implementations
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.common import cardinality
-from grpc.framework.interfaces.face import utilities as face_utilities
+try:
+  # THESE ELEMENTS WILL BE DEPRECATED.
+  # Please use the generated *_pb2_grpc.py files instead.
+  import grpc
+  from grpc.framework.common import cardinality
+  from grpc.framework.interfaces.face import utilities as face_utilities
+  from grpc.beta import implementations as beta_implementations
+  from grpc.beta import interfaces as beta_interfaces
 
 
-class GreeterStub(object):
-  """The greeting service definition.
-  """
-
-  def __init__(self, channel):
-    """Constructor.
-
-    Args:
-      channel: A grpc.Channel.
+  class GreeterStub(object):
+    """The greeting service definition.
     """
-    self.SayHello = channel.unary_unary(
-        '/helloworld.Greeter/SayHello',
-        request_serializer=HelloRequest.SerializeToString,
-        response_deserializer=HelloReply.FromString,
-        )
+
+    def __init__(self, channel):
+      """Constructor.
+
+      Args:
+        channel: A grpc.Channel.
+      """
+      self.SayHello = channel.unary_unary(
+          '/helloworld.Greeter/SayHello',
+          request_serializer=HelloRequest.SerializeToString,
+          response_deserializer=HelloReply.FromString,
+          )
 
 
-class GreeterServicer(object):
-  """The greeting service definition.
-  """
-
-  def SayHello(self, request, context):
-    """Sends a greeting
+  class GreeterServicer(object):
+    """The greeting service definition.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+
+    def SayHello(self, request, context):
+      """Sends a greeting
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
 
 
-def add_GreeterServicer_to_server(servicer, server):
-  rpc_method_handlers = {
-      'SayHello': grpc.unary_unary_rpc_method_handler(
-          servicer.SayHello,
-          request_deserializer=HelloRequest.FromString,
-          response_serializer=HelloReply.SerializeToString,
-      ),
-  }
-  generic_handler = grpc.method_handlers_generic_handler(
-      'helloworld.Greeter', rpc_method_handlers)
-  server.add_generic_rpc_handlers((generic_handler,))
+  def add_GreeterServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+        'SayHello': grpc.unary_unary_rpc_method_handler(
+            servicer.SayHello,
+            request_deserializer=HelloRequest.FromString,
+            response_serializer=HelloReply.SerializeToString,
+        ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+        'helloworld.Greeter', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
 
 
-class BetaGreeterServicer(object):
-  """The greeting service definition.
-  """
-  def SayHello(self, request, context):
-    """Sends a greeting
+  class BetaGreeterServicer(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """The greeting service definition.
     """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def SayHello(self, request, context):
+      """Sends a greeting
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
 
 
-class BetaGreeterStub(object):
-  """The greeting service definition.
-  """
-  def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
-    """Sends a greeting
+  class BetaGreeterStub(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """The greeting service definition.
     """
-    raise NotImplementedError()
-  SayHello.future = None
+    def SayHello(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """Sends a greeting
+      """
+      raise NotImplementedError()
+    SayHello.future = None
 
 
-def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
-  request_deserializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloRequest.FromString,
-  }
-  response_serializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString,
-  }
-  method_implementations = {
-    ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
-  }
-  server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
-  return beta_implementations.server(method_implementations, options=server_options)
+  def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_deserializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloRequest.FromString,
+    }
+    response_serializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloReply.SerializeToString,
+    }
+    method_implementations = {
+      ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
+    }
+    server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
+    return beta_implementations.server(method_implementations, options=server_options)
 
 
-def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
-  request_serializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString,
-  }
-  response_deserializers = {
-    ('helloworld.Greeter', 'SayHello'): HelloReply.FromString,
-  }
-  cardinalities = {
-    'SayHello': cardinality.Cardinality.UNARY_UNARY,
-  }
-  stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
-  return beta_implementations.dynamic_stub(channel, 'helloworld.Greeter', cardinalities, options=stub_options)
+  def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_serializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloRequest.SerializeToString,
+    }
+    response_deserializers = {
+      ('helloworld.Greeter', 'SayHello'): HelloReply.FromString,
+    }
+    cardinalities = {
+      'SayHello': cardinality.Cardinality.UNARY_UNARY,
+    }
+    stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
+    return beta_implementations.dynamic_stub(channel, 'helloworld.Greeter', cardinalities, options=stub_options)
+except ImportError:
+  pass
 # @@protoc_insertion_point(module_scope)
diff --git a/examples/python/multiplex/helloworld_pb2_grpc.py b/examples/python/multiplex/helloworld_pb2_grpc.py
new file mode 100644
index 0000000..682dc36
--- /dev/null
+++ b/examples/python/multiplex/helloworld_pb2_grpc.py
@@ -0,0 +1,47 @@
+import grpc
+from grpc.framework.common import cardinality
+from grpc.framework.interfaces.face import utilities as face_utilities
+
+import helloworld_pb2 as helloworld__pb2
+
+
+class GreeterStub(object):
+  """The greeting service definition.
+  """
+
+  def __init__(self, channel):
+    """Constructor.
+
+    Args:
+      channel: A grpc.Channel.
+    """
+    self.SayHello = channel.unary_unary(
+        '/helloworld.Greeter/SayHello',
+        request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
+        response_deserializer=helloworld__pb2.HelloReply.FromString,
+        )
+
+
+class GreeterServicer(object):
+  """The greeting service definition.
+  """
+
+  def SayHello(self, request, context):
+    """Sends a greeting
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+
+def add_GreeterServicer_to_server(servicer, server):
+  rpc_method_handlers = {
+      'SayHello': grpc.unary_unary_rpc_method_handler(
+          servicer.SayHello,
+          request_deserializer=helloworld__pb2.HelloRequest.FromString,
+          response_serializer=helloworld__pb2.HelloReply.SerializeToString,
+      ),
+  }
+  generic_handler = grpc.method_handlers_generic_handler(
+      'helloworld.Greeter', rpc_method_handlers)
+  server.add_generic_rpc_handlers((generic_handler,))
diff --git a/examples/python/multiplex/multiplex_client.py b/examples/python/multiplex/multiplex_client.py
index 2e81629..b2d2021 100644
--- a/examples/python/multiplex/multiplex_client.py
+++ b/examples/python/multiplex/multiplex_client.py
@@ -37,7 +37,9 @@
 import grpc
 
 import helloworld_pb2
+import helloworld_pb2_grpc
 import route_guide_pb2
+import route_guide_pb2_grpc
 import route_guide_resources
 
 
@@ -120,8 +122,8 @@
 
 def run():
   channel = grpc.insecure_channel('localhost:50051')
-  greeter_stub = helloworld_pb2.GreeterStub(channel)
-  route_guide_stub = route_guide_pb2.RouteGuideStub(channel)
+  greeter_stub = helloworld_pb2_grpc.GreeterStub(channel)
+  route_guide_stub = route_guide_pb2_grpc.RouteGuideStub(channel)
   greeter_response = greeter_stub.SayHello(
       helloworld_pb2.HelloRequest(name='you'))
   print("Greeter client received: " + greeter_response.message)
diff --git a/examples/python/multiplex/multiplex_server.py b/examples/python/multiplex/multiplex_server.py
index 32a4ee4..b8b32e7 100644
--- a/examples/python/multiplex/multiplex_server.py
+++ b/examples/python/multiplex/multiplex_server.py
@@ -36,7 +36,9 @@
 import grpc
 
 import helloworld_pb2
+import helloworld_pb2_grpc
 import route_guide_pb2
+import route_guide_pb2_grpc
 import route_guide_resources
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
@@ -70,13 +72,13 @@
   return R * c;
 
 
-class _GreeterServicer(helloworld_pb2.GreeterServicer):
+class _GreeterServicer(helloworld_pb2_grpc.GreeterServicer):
 
   def SayHello(self, request, context):
     return helloworld_pb2.HelloReply(message='Hello, {}!'.format(request.name))
 
 
-class _RouteGuideServicer(route_guide_pb2.RouteGuideServicer):
+class _RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
   """Provides methods that implement functionality of route guide server."""
 
   def __init__(self):
@@ -133,8 +135,8 @@
 
 def serve():
   server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
-  helloworld_pb2.add_GreeterServicer_to_server(_GreeterServicer(), server)
-  route_guide_pb2.add_RouteGuideServicer_to_server(
+  helloworld_pb2_grpc.add_GreeterServicer_to_server(_GreeterServicer(), server)
+  route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
       _RouteGuideServicer(), server)
   server.add_insecure_port('[::]:50051')
   server.start()
diff --git a/examples/python/multiplex/route_guide_pb2.py b/examples/python/multiplex/route_guide_pb2.py
index 924e186..e6775eb 100644
--- a/examples/python/multiplex/route_guide_pb2.py
+++ b/examples/python/multiplex/route_guide_pb2.py
@@ -277,240 +277,265 @@
 
 DESCRIPTOR.has_options = True
 DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.routeguideB\017RouteGuideProtoP\001\242\002\003RTG'))
-import grpc
-from grpc.beta import implementations as beta_implementations
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.common import cardinality
-from grpc.framework.interfaces.face import utilities as face_utilities
+try:
+  # THESE ELEMENTS WILL BE DEPRECATED.
+  # Please use the generated *_pb2_grpc.py files instead.
+  import grpc
+  from grpc.framework.common import cardinality
+  from grpc.framework.interfaces.face import utilities as face_utilities
+  from grpc.beta import implementations as beta_implementations
+  from grpc.beta import interfaces as beta_interfaces
 
 
-class RouteGuideStub(object):
-  """Interface exported by the server.
-  """
-
-  def __init__(self, channel):
-    """Constructor.
-
-    Args:
-      channel: A grpc.Channel.
+  class RouteGuideStub(object):
+    """Interface exported by the server.
     """
-    self.GetFeature = channel.unary_unary(
-        '/routeguide.RouteGuide/GetFeature',
-        request_serializer=Point.SerializeToString,
-        response_deserializer=Feature.FromString,
-        )
-    self.ListFeatures = channel.unary_stream(
-        '/routeguide.RouteGuide/ListFeatures',
-        request_serializer=Rectangle.SerializeToString,
-        response_deserializer=Feature.FromString,
-        )
-    self.RecordRoute = channel.stream_unary(
-        '/routeguide.RouteGuide/RecordRoute',
-        request_serializer=Point.SerializeToString,
-        response_deserializer=RouteSummary.FromString,
-        )
-    self.RouteChat = channel.stream_stream(
-        '/routeguide.RouteGuide/RouteChat',
-        request_serializer=RouteNote.SerializeToString,
-        response_deserializer=RouteNote.FromString,
-        )
+
+    def __init__(self, channel):
+      """Constructor.
+
+      Args:
+        channel: A grpc.Channel.
+      """
+      self.GetFeature = channel.unary_unary(
+          '/routeguide.RouteGuide/GetFeature',
+          request_serializer=Point.SerializeToString,
+          response_deserializer=Feature.FromString,
+          )
+      self.ListFeatures = channel.unary_stream(
+          '/routeguide.RouteGuide/ListFeatures',
+          request_serializer=Rectangle.SerializeToString,
+          response_deserializer=Feature.FromString,
+          )
+      self.RecordRoute = channel.stream_unary(
+          '/routeguide.RouteGuide/RecordRoute',
+          request_serializer=Point.SerializeToString,
+          response_deserializer=RouteSummary.FromString,
+          )
+      self.RouteChat = channel.stream_stream(
+          '/routeguide.RouteGuide/RouteChat',
+          request_serializer=RouteNote.SerializeToString,
+          response_deserializer=RouteNote.FromString,
+          )
 
 
-class RouteGuideServicer(object):
-  """Interface exported by the server.
-  """
-
-  def GetFeature(self, request, context):
-    """A simple RPC.
-
-    Obtains the feature at a given position.
-
-    A feature with an empty name is returned if there's no feature at the given
-    position.
+  class RouteGuideServicer(object):
+    """Interface exported by the server.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
 
-  def ListFeatures(self, request, context):
-    """A server-to-client streaming RPC.
+    def GetFeature(self, request, context):
+      """A simple RPC.
 
-    Obtains the Features available within the given Rectangle.  Results are
-    streamed rather than returned at once (e.g. in a response message with a
-    repeated field), as the rectangle may cover a large area and contain a
-    huge number of features.
+      Obtains the feature at a given position.
+
+      A feature with an empty name is returned if there's no feature at the given
+      position.
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def ListFeatures(self, request, context):
+      """A server-to-client streaming RPC.
+
+      Obtains the Features available within the given Rectangle.  Results are
+      streamed rather than returned at once (e.g. in a response message with a
+      repeated field), as the rectangle may cover a large area and contain a
+      huge number of features.
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def RecordRoute(self, request_iterator, context):
+      """A client-to-server streaming RPC.
+
+      Accepts a stream of Points on a route being traversed, returning a
+      RouteSummary when traversal is completed.
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def RouteChat(self, request_iterator, context):
+      """A Bidirectional streaming RPC.
+
+      Accepts a stream of RouteNotes sent while a route is being traversed,
+      while receiving other RouteNotes (e.g. from other users).
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+
+  def add_RouteGuideServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+        'GetFeature': grpc.unary_unary_rpc_method_handler(
+            servicer.GetFeature,
+            request_deserializer=Point.FromString,
+            response_serializer=Feature.SerializeToString,
+        ),
+        'ListFeatures': grpc.unary_stream_rpc_method_handler(
+            servicer.ListFeatures,
+            request_deserializer=Rectangle.FromString,
+            response_serializer=Feature.SerializeToString,
+        ),
+        'RecordRoute': grpc.stream_unary_rpc_method_handler(
+            servicer.RecordRoute,
+            request_deserializer=Point.FromString,
+            response_serializer=RouteSummary.SerializeToString,
+        ),
+        'RouteChat': grpc.stream_stream_rpc_method_handler(
+            servicer.RouteChat,
+            request_deserializer=RouteNote.FromString,
+            response_serializer=RouteNote.SerializeToString,
+        ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+        'routeguide.RouteGuide', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+  class BetaRouteGuideServicer(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """Interface exported by the server.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+    def GetFeature(self, request, context):
+      """A simple RPC.
 
-  def RecordRoute(self, request_iterator, context):
-    """A client-to-server streaming RPC.
+      Obtains the feature at a given position.
 
-    Accepts a stream of Points on a route being traversed, returning a
-    RouteSummary when traversal is completed.
+      A feature with an empty name is returned if there's no feature at the given
+      position.
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def ListFeatures(self, request, context):
+      """A server-to-client streaming RPC.
+
+      Obtains the Features available within the given Rectangle.  Results are
+      streamed rather than returned at once (e.g. in a response message with a
+      repeated field), as the rectangle may cover a large area and contain a
+      huge number of features.
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def RecordRoute(self, request_iterator, context):
+      """A client-to-server streaming RPC.
+
+      Accepts a stream of Points on a route being traversed, returning a
+      RouteSummary when traversal is completed.
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def RouteChat(self, request_iterator, context):
+      """A Bidirectional streaming RPC.
+
+      Accepts a stream of RouteNotes sent while a route is being traversed,
+      while receiving other RouteNotes (e.g. from other users).
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+
+
+  class BetaRouteGuideStub(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """Interface exported by the server.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+    def GetFeature(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A simple RPC.
 
-  def RouteChat(self, request_iterator, context):
-    """A Bidirectional streaming RPC.
+      Obtains the feature at a given position.
 
-    Accepts a stream of RouteNotes sent while a route is being traversed,
-    while receiving other RouteNotes (e.g. from other users).
-    """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+      A feature with an empty name is returned if there's no feature at the given
+      position.
+      """
+      raise NotImplementedError()
+    GetFeature.future = None
+    def ListFeatures(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A server-to-client streaming RPC.
+
+      Obtains the Features available within the given Rectangle.  Results are
+      streamed rather than returned at once (e.g. in a response message with a
+      repeated field), as the rectangle may cover a large area and contain a
+      huge number of features.
+      """
+      raise NotImplementedError()
+    def RecordRoute(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A client-to-server streaming RPC.
+
+      Accepts a stream of Points on a route being traversed, returning a
+      RouteSummary when traversal is completed.
+      """
+      raise NotImplementedError()
+    RecordRoute.future = None
+    def RouteChat(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A Bidirectional streaming RPC.
+
+      Accepts a stream of RouteNotes sent while a route is being traversed,
+      while receiving other RouteNotes (e.g. from other users).
+      """
+      raise NotImplementedError()
 
 
-def add_RouteGuideServicer_to_server(servicer, server):
-  rpc_method_handlers = {
-      'GetFeature': grpc.unary_unary_rpc_method_handler(
-          servicer.GetFeature,
-          request_deserializer=Point.FromString,
-          response_serializer=Feature.SerializeToString,
-      ),
-      'ListFeatures': grpc.unary_stream_rpc_method_handler(
-          servicer.ListFeatures,
-          request_deserializer=Rectangle.FromString,
-          response_serializer=Feature.SerializeToString,
-      ),
-      'RecordRoute': grpc.stream_unary_rpc_method_handler(
-          servicer.RecordRoute,
-          request_deserializer=Point.FromString,
-          response_serializer=RouteSummary.SerializeToString,
-      ),
-      'RouteChat': grpc.stream_stream_rpc_method_handler(
-          servicer.RouteChat,
-          request_deserializer=RouteNote.FromString,
-          response_serializer=RouteNote.SerializeToString,
-      ),
-  }
-  generic_handler = grpc.method_handlers_generic_handler(
-      'routeguide.RouteGuide', rpc_method_handlers)
-  server.add_generic_rpc_handlers((generic_handler,))
+  def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_deserializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Point.FromString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.FromString,
+      ('routeguide.RouteGuide', 'RecordRoute'): Point.FromString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
+    }
+    response_serializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Feature.SerializeToString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Feature.SerializeToString,
+      ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.SerializeToString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
+    }
+    method_implementations = {
+      ('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature),
+      ('routeguide.RouteGuide', 'ListFeatures'): face_utilities.unary_stream_inline(servicer.ListFeatures),
+      ('routeguide.RouteGuide', 'RecordRoute'): face_utilities.stream_unary_inline(servicer.RecordRoute),
+      ('routeguide.RouteGuide', 'RouteChat'): face_utilities.stream_stream_inline(servicer.RouteChat),
+    }
+    server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
+    return beta_implementations.server(method_implementations, options=server_options)
 
 
-class BetaRouteGuideServicer(object):
-  """Interface exported by the server.
-  """
-  def GetFeature(self, request, context):
-    """A simple RPC.
+  def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
+    """The Beta API is deprecated for 0.15.0 and later.
 
-    Obtains the feature at a given position.
-
-    A feature with an empty name is returned if there's no feature at the given
-    position.
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-  def ListFeatures(self, request, context):
-    """A server-to-client streaming RPC.
-
-    Obtains the Features available within the given Rectangle.  Results are
-    streamed rather than returned at once (e.g. in a response message with a
-    repeated field), as the rectangle may cover a large area and contain a
-    huge number of features.
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-  def RecordRoute(self, request_iterator, context):
-    """A client-to-server streaming RPC.
-
-    Accepts a stream of Points on a route being traversed, returning a
-    RouteSummary when traversal is completed.
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-  def RouteChat(self, request_iterator, context):
-    """A Bidirectional streaming RPC.
-
-    Accepts a stream of RouteNotes sent while a route is being traversed,
-    while receiving other RouteNotes (e.g. from other users).
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-
-
-class BetaRouteGuideStub(object):
-  """Interface exported by the server.
-  """
-  def GetFeature(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A simple RPC.
-
-    Obtains the feature at a given position.
-
-    A feature with an empty name is returned if there's no feature at the given
-    position.
-    """
-    raise NotImplementedError()
-  GetFeature.future = None
-  def ListFeatures(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A server-to-client streaming RPC.
-
-    Obtains the Features available within the given Rectangle.  Results are
-    streamed rather than returned at once (e.g. in a response message with a
-    repeated field), as the rectangle may cover a large area and contain a
-    huge number of features.
-    """
-    raise NotImplementedError()
-  def RecordRoute(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A client-to-server streaming RPC.
-
-    Accepts a stream of Points on a route being traversed, returning a
-    RouteSummary when traversal is completed.
-    """
-    raise NotImplementedError()
-  RecordRoute.future = None
-  def RouteChat(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A Bidirectional streaming RPC.
-
-    Accepts a stream of RouteNotes sent while a route is being traversed,
-    while receiving other RouteNotes (e.g. from other users).
-    """
-    raise NotImplementedError()
-
-
-def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
-  request_deserializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Point.FromString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.FromString,
-    ('routeguide.RouteGuide', 'RecordRoute'): Point.FromString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
-  }
-  response_serializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Feature.SerializeToString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Feature.SerializeToString,
-    ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.SerializeToString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
-  }
-  method_implementations = {
-    ('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature),
-    ('routeguide.RouteGuide', 'ListFeatures'): face_utilities.unary_stream_inline(servicer.ListFeatures),
-    ('routeguide.RouteGuide', 'RecordRoute'): face_utilities.stream_unary_inline(servicer.RecordRoute),
-    ('routeguide.RouteGuide', 'RouteChat'): face_utilities.stream_stream_inline(servicer.RouteChat),
-  }
-  server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
-  return beta_implementations.server(method_implementations, options=server_options)
-
-
-def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
-  request_serializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Point.SerializeToString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.SerializeToString,
-    ('routeguide.RouteGuide', 'RecordRoute'): Point.SerializeToString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
-  }
-  response_deserializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Feature.FromString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Feature.FromString,
-    ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.FromString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
-  }
-  cardinalities = {
-    'GetFeature': cardinality.Cardinality.UNARY_UNARY,
-    'ListFeatures': cardinality.Cardinality.UNARY_STREAM,
-    'RecordRoute': cardinality.Cardinality.STREAM_UNARY,
-    'RouteChat': cardinality.Cardinality.STREAM_STREAM,
-  }
-  stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
-  return beta_implementations.dynamic_stub(channel, 'routeguide.RouteGuide', cardinalities, options=stub_options)
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_serializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Point.SerializeToString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.SerializeToString,
+      ('routeguide.RouteGuide', 'RecordRoute'): Point.SerializeToString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
+    }
+    response_deserializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Feature.FromString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Feature.FromString,
+      ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.FromString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
+    }
+    cardinalities = {
+      'GetFeature': cardinality.Cardinality.UNARY_UNARY,
+      'ListFeatures': cardinality.Cardinality.UNARY_STREAM,
+      'RecordRoute': cardinality.Cardinality.STREAM_UNARY,
+      'RouteChat': cardinality.Cardinality.STREAM_STREAM,
+    }
+    stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
+    return beta_implementations.dynamic_stub(channel, 'routeguide.RouteGuide', cardinalities, options=stub_options)
+except ImportError:
+  pass
 # @@protoc_insertion_point(module_scope)
diff --git a/examples/python/multiplex/route_guide_pb2_grpc.py b/examples/python/multiplex/route_guide_pb2_grpc.py
new file mode 100644
index 0000000..27b24c7
--- /dev/null
+++ b/examples/python/multiplex/route_guide_pb2_grpc.py
@@ -0,0 +1,114 @@
+import grpc
+from grpc.framework.common import cardinality
+from grpc.framework.interfaces.face import utilities as face_utilities
+
+import route_guide_pb2 as route__guide__pb2
+
+
+class RouteGuideStub(object):
+  """Interface exported by the server.
+  """
+
+  def __init__(self, channel):
+    """Constructor.
+
+    Args:
+      channel: A grpc.Channel.
+    """
+    self.GetFeature = channel.unary_unary(
+        '/routeguide.RouteGuide/GetFeature',
+        request_serializer=route__guide__pb2.Point.SerializeToString,
+        response_deserializer=route__guide__pb2.Feature.FromString,
+        )
+    self.ListFeatures = channel.unary_stream(
+        '/routeguide.RouteGuide/ListFeatures',
+        request_serializer=route__guide__pb2.Rectangle.SerializeToString,
+        response_deserializer=route__guide__pb2.Feature.FromString,
+        )
+    self.RecordRoute = channel.stream_unary(
+        '/routeguide.RouteGuide/RecordRoute',
+        request_serializer=route__guide__pb2.Point.SerializeToString,
+        response_deserializer=route__guide__pb2.RouteSummary.FromString,
+        )
+    self.RouteChat = channel.stream_stream(
+        '/routeguide.RouteGuide/RouteChat',
+        request_serializer=route__guide__pb2.RouteNote.SerializeToString,
+        response_deserializer=route__guide__pb2.RouteNote.FromString,
+        )
+
+
+class RouteGuideServicer(object):
+  """Interface exported by the server.
+  """
+
+  def GetFeature(self, request, context):
+    """A simple RPC.
+
+    Obtains the feature at a given position.
+
+    A feature with an empty name is returned if there's no feature at the given
+    position.
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+  def ListFeatures(self, request, context):
+    """A server-to-client streaming RPC.
+
+    Obtains the Features available within the given Rectangle.  Results are
+    streamed rather than returned at once (e.g. in a response message with a
+    repeated field), as the rectangle may cover a large area and contain a
+    huge number of features.
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+  def RecordRoute(self, request_iterator, context):
+    """A client-to-server streaming RPC.
+
+    Accepts a stream of Points on a route being traversed, returning a
+    RouteSummary when traversal is completed.
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+  def RouteChat(self, request_iterator, context):
+    """A Bidirectional streaming RPC.
+
+    Accepts a stream of RouteNotes sent while a route is being traversed,
+    while receiving other RouteNotes (e.g. from other users).
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+
+def add_RouteGuideServicer_to_server(servicer, server):
+  rpc_method_handlers = {
+      'GetFeature': grpc.unary_unary_rpc_method_handler(
+          servicer.GetFeature,
+          request_deserializer=route__guide__pb2.Point.FromString,
+          response_serializer=route__guide__pb2.Feature.SerializeToString,
+      ),
+      'ListFeatures': grpc.unary_stream_rpc_method_handler(
+          servicer.ListFeatures,
+          request_deserializer=route__guide__pb2.Rectangle.FromString,
+          response_serializer=route__guide__pb2.Feature.SerializeToString,
+      ),
+      'RecordRoute': grpc.stream_unary_rpc_method_handler(
+          servicer.RecordRoute,
+          request_deserializer=route__guide__pb2.Point.FromString,
+          response_serializer=route__guide__pb2.RouteSummary.SerializeToString,
+      ),
+      'RouteChat': grpc.stream_stream_rpc_method_handler(
+          servicer.RouteChat,
+          request_deserializer=route__guide__pb2.RouteNote.FromString,
+          response_serializer=route__guide__pb2.RouteNote.SerializeToString,
+      ),
+  }
+  generic_handler = grpc.method_handlers_generic_handler(
+      'routeguide.RouteGuide', rpc_method_handlers)
+  server.add_generic_rpc_handlers((generic_handler,))
diff --git a/examples/python/multiplex/run_codegen.py b/examples/python/multiplex/run_codegen.py
old mode 100755
new mode 100644
index 7922a0f..89ac9c8
--- a/examples/python/multiplex/run_codegen.py
+++ b/examples/python/multiplex/run_codegen.py
@@ -29,7 +29,7 @@
 
 """Generates protocol messages and gRPC stubs."""
 
-from grpc.tools import protoc
+from grpc_tools import protoc
 
 protoc.main(
     (
diff --git a/examples/python/route_guide/route_guide_client.py b/examples/python/route_guide/route_guide_client.py
index 8a80ed8..d295523 100644
--- a/examples/python/route_guide/route_guide_client.py
+++ b/examples/python/route_guide/route_guide_client.py
@@ -37,6 +37,7 @@
 import grpc
 
 import route_guide_pb2
+import route_guide_pb2_grpc
 import route_guide_resources
 
 
@@ -116,7 +117,7 @@
 
 def run():
   channel = grpc.insecure_channel('localhost:50051')
-  stub = route_guide_pb2.RouteGuideStub(channel)
+  stub = route_guide_pb2_grpc.RouteGuideStub(channel)
   print("-------------- GetFeature --------------")
   guide_get_feature(stub)
   print("-------------- ListFeatures --------------")
diff --git a/examples/python/route_guide/route_guide_pb2.py b/examples/python/route_guide/route_guide_pb2.py
index 924e186..e6775eb 100644
--- a/examples/python/route_guide/route_guide_pb2.py
+++ b/examples/python/route_guide/route_guide_pb2.py
@@ -277,240 +277,265 @@
 
 DESCRIPTOR.has_options = True
 DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.routeguideB\017RouteGuideProtoP\001\242\002\003RTG'))
-import grpc
-from grpc.beta import implementations as beta_implementations
-from grpc.beta import interfaces as beta_interfaces
-from grpc.framework.common import cardinality
-from grpc.framework.interfaces.face import utilities as face_utilities
+try:
+  # THESE ELEMENTS WILL BE DEPRECATED.
+  # Please use the generated *_pb2_grpc.py files instead.
+  import grpc
+  from grpc.framework.common import cardinality
+  from grpc.framework.interfaces.face import utilities as face_utilities
+  from grpc.beta import implementations as beta_implementations
+  from grpc.beta import interfaces as beta_interfaces
 
 
-class RouteGuideStub(object):
-  """Interface exported by the server.
-  """
-
-  def __init__(self, channel):
-    """Constructor.
-
-    Args:
-      channel: A grpc.Channel.
+  class RouteGuideStub(object):
+    """Interface exported by the server.
     """
-    self.GetFeature = channel.unary_unary(
-        '/routeguide.RouteGuide/GetFeature',
-        request_serializer=Point.SerializeToString,
-        response_deserializer=Feature.FromString,
-        )
-    self.ListFeatures = channel.unary_stream(
-        '/routeguide.RouteGuide/ListFeatures',
-        request_serializer=Rectangle.SerializeToString,
-        response_deserializer=Feature.FromString,
-        )
-    self.RecordRoute = channel.stream_unary(
-        '/routeguide.RouteGuide/RecordRoute',
-        request_serializer=Point.SerializeToString,
-        response_deserializer=RouteSummary.FromString,
-        )
-    self.RouteChat = channel.stream_stream(
-        '/routeguide.RouteGuide/RouteChat',
-        request_serializer=RouteNote.SerializeToString,
-        response_deserializer=RouteNote.FromString,
-        )
+
+    def __init__(self, channel):
+      """Constructor.
+
+      Args:
+        channel: A grpc.Channel.
+      """
+      self.GetFeature = channel.unary_unary(
+          '/routeguide.RouteGuide/GetFeature',
+          request_serializer=Point.SerializeToString,
+          response_deserializer=Feature.FromString,
+          )
+      self.ListFeatures = channel.unary_stream(
+          '/routeguide.RouteGuide/ListFeatures',
+          request_serializer=Rectangle.SerializeToString,
+          response_deserializer=Feature.FromString,
+          )
+      self.RecordRoute = channel.stream_unary(
+          '/routeguide.RouteGuide/RecordRoute',
+          request_serializer=Point.SerializeToString,
+          response_deserializer=RouteSummary.FromString,
+          )
+      self.RouteChat = channel.stream_stream(
+          '/routeguide.RouteGuide/RouteChat',
+          request_serializer=RouteNote.SerializeToString,
+          response_deserializer=RouteNote.FromString,
+          )
 
 
-class RouteGuideServicer(object):
-  """Interface exported by the server.
-  """
-
-  def GetFeature(self, request, context):
-    """A simple RPC.
-
-    Obtains the feature at a given position.
-
-    A feature with an empty name is returned if there's no feature at the given
-    position.
+  class RouteGuideServicer(object):
+    """Interface exported by the server.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
 
-  def ListFeatures(self, request, context):
-    """A server-to-client streaming RPC.
+    def GetFeature(self, request, context):
+      """A simple RPC.
 
-    Obtains the Features available within the given Rectangle.  Results are
-    streamed rather than returned at once (e.g. in a response message with a
-    repeated field), as the rectangle may cover a large area and contain a
-    huge number of features.
+      Obtains the feature at a given position.
+
+      A feature with an empty name is returned if there's no feature at the given
+      position.
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def ListFeatures(self, request, context):
+      """A server-to-client streaming RPC.
+
+      Obtains the Features available within the given Rectangle.  Results are
+      streamed rather than returned at once (e.g. in a response message with a
+      repeated field), as the rectangle may cover a large area and contain a
+      huge number of features.
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def RecordRoute(self, request_iterator, context):
+      """A client-to-server streaming RPC.
+
+      Accepts a stream of Points on a route being traversed, returning a
+      RouteSummary when traversal is completed.
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+    def RouteChat(self, request_iterator, context):
+      """A Bidirectional streaming RPC.
+
+      Accepts a stream of RouteNotes sent while a route is being traversed,
+      while receiving other RouteNotes (e.g. from other users).
+      """
+      context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+      context.set_details('Method not implemented!')
+      raise NotImplementedError('Method not implemented!')
+
+
+  def add_RouteGuideServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+        'GetFeature': grpc.unary_unary_rpc_method_handler(
+            servicer.GetFeature,
+            request_deserializer=Point.FromString,
+            response_serializer=Feature.SerializeToString,
+        ),
+        'ListFeatures': grpc.unary_stream_rpc_method_handler(
+            servicer.ListFeatures,
+            request_deserializer=Rectangle.FromString,
+            response_serializer=Feature.SerializeToString,
+        ),
+        'RecordRoute': grpc.stream_unary_rpc_method_handler(
+            servicer.RecordRoute,
+            request_deserializer=Point.FromString,
+            response_serializer=RouteSummary.SerializeToString,
+        ),
+        'RouteChat': grpc.stream_stream_rpc_method_handler(
+            servicer.RouteChat,
+            request_deserializer=RouteNote.FromString,
+            response_serializer=RouteNote.SerializeToString,
+        ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+        'routeguide.RouteGuide', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+  class BetaRouteGuideServicer(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """Interface exported by the server.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+    def GetFeature(self, request, context):
+      """A simple RPC.
 
-  def RecordRoute(self, request_iterator, context):
-    """A client-to-server streaming RPC.
+      Obtains the feature at a given position.
 
-    Accepts a stream of Points on a route being traversed, returning a
-    RouteSummary when traversal is completed.
+      A feature with an empty name is returned if there's no feature at the given
+      position.
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def ListFeatures(self, request, context):
+      """A server-to-client streaming RPC.
+
+      Obtains the Features available within the given Rectangle.  Results are
+      streamed rather than returned at once (e.g. in a response message with a
+      repeated field), as the rectangle may cover a large area and contain a
+      huge number of features.
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def RecordRoute(self, request_iterator, context):
+      """A client-to-server streaming RPC.
+
+      Accepts a stream of Points on a route being traversed, returning a
+      RouteSummary when traversal is completed.
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+    def RouteChat(self, request_iterator, context):
+      """A Bidirectional streaming RPC.
+
+      Accepts a stream of RouteNotes sent while a route is being traversed,
+      while receiving other RouteNotes (e.g. from other users).
+      """
+      context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
+
+
+  class BetaRouteGuideStub(object):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This class was generated
+    only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0."""
+    """Interface exported by the server.
     """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+    def GetFeature(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A simple RPC.
 
-  def RouteChat(self, request_iterator, context):
-    """A Bidirectional streaming RPC.
+      Obtains the feature at a given position.
 
-    Accepts a stream of RouteNotes sent while a route is being traversed,
-    while receiving other RouteNotes (e.g. from other users).
-    """
-    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
-    context.set_details('Method not implemented!')
-    raise NotImplementedError('Method not implemented!')
+      A feature with an empty name is returned if there's no feature at the given
+      position.
+      """
+      raise NotImplementedError()
+    GetFeature.future = None
+    def ListFeatures(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A server-to-client streaming RPC.
+
+      Obtains the Features available within the given Rectangle.  Results are
+      streamed rather than returned at once (e.g. in a response message with a
+      repeated field), as the rectangle may cover a large area and contain a
+      huge number of features.
+      """
+      raise NotImplementedError()
+    def RecordRoute(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A client-to-server streaming RPC.
+
+      Accepts a stream of Points on a route being traversed, returning a
+      RouteSummary when traversal is completed.
+      """
+      raise NotImplementedError()
+    RecordRoute.future = None
+    def RouteChat(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
+      """A Bidirectional streaming RPC.
+
+      Accepts a stream of RouteNotes sent while a route is being traversed,
+      while receiving other RouteNotes (e.g. from other users).
+      """
+      raise NotImplementedError()
 
 
-def add_RouteGuideServicer_to_server(servicer, server):
-  rpc_method_handlers = {
-      'GetFeature': grpc.unary_unary_rpc_method_handler(
-          servicer.GetFeature,
-          request_deserializer=Point.FromString,
-          response_serializer=Feature.SerializeToString,
-      ),
-      'ListFeatures': grpc.unary_stream_rpc_method_handler(
-          servicer.ListFeatures,
-          request_deserializer=Rectangle.FromString,
-          response_serializer=Feature.SerializeToString,
-      ),
-      'RecordRoute': grpc.stream_unary_rpc_method_handler(
-          servicer.RecordRoute,
-          request_deserializer=Point.FromString,
-          response_serializer=RouteSummary.SerializeToString,
-      ),
-      'RouteChat': grpc.stream_stream_rpc_method_handler(
-          servicer.RouteChat,
-          request_deserializer=RouteNote.FromString,
-          response_serializer=RouteNote.SerializeToString,
-      ),
-  }
-  generic_handler = grpc.method_handlers_generic_handler(
-      'routeguide.RouteGuide', rpc_method_handlers)
-  server.add_generic_rpc_handlers((generic_handler,))
+  def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
+    """The Beta API is deprecated for 0.15.0 and later.
+
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_deserializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Point.FromString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.FromString,
+      ('routeguide.RouteGuide', 'RecordRoute'): Point.FromString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
+    }
+    response_serializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Feature.SerializeToString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Feature.SerializeToString,
+      ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.SerializeToString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
+    }
+    method_implementations = {
+      ('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature),
+      ('routeguide.RouteGuide', 'ListFeatures'): face_utilities.unary_stream_inline(servicer.ListFeatures),
+      ('routeguide.RouteGuide', 'RecordRoute'): face_utilities.stream_unary_inline(servicer.RecordRoute),
+      ('routeguide.RouteGuide', 'RouteChat'): face_utilities.stream_stream_inline(servicer.RouteChat),
+    }
+    server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
+    return beta_implementations.server(method_implementations, options=server_options)
 
 
-class BetaRouteGuideServicer(object):
-  """Interface exported by the server.
-  """
-  def GetFeature(self, request, context):
-    """A simple RPC.
+  def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
+    """The Beta API is deprecated for 0.15.0 and later.
 
-    Obtains the feature at a given position.
-
-    A feature with an empty name is returned if there's no feature at the given
-    position.
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-  def ListFeatures(self, request, context):
-    """A server-to-client streaming RPC.
-
-    Obtains the Features available within the given Rectangle.  Results are
-    streamed rather than returned at once (e.g. in a response message with a
-    repeated field), as the rectangle may cover a large area and contain a
-    huge number of features.
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-  def RecordRoute(self, request_iterator, context):
-    """A client-to-server streaming RPC.
-
-    Accepts a stream of Points on a route being traversed, returning a
-    RouteSummary when traversal is completed.
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-  def RouteChat(self, request_iterator, context):
-    """A Bidirectional streaming RPC.
-
-    Accepts a stream of RouteNotes sent while a route is being traversed,
-    while receiving other RouteNotes (e.g. from other users).
-    """
-    context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)
-
-
-class BetaRouteGuideStub(object):
-  """Interface exported by the server.
-  """
-  def GetFeature(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A simple RPC.
-
-    Obtains the feature at a given position.
-
-    A feature with an empty name is returned if there's no feature at the given
-    position.
-    """
-    raise NotImplementedError()
-  GetFeature.future = None
-  def ListFeatures(self, request, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A server-to-client streaming RPC.
-
-    Obtains the Features available within the given Rectangle.  Results are
-    streamed rather than returned at once (e.g. in a response message with a
-    repeated field), as the rectangle may cover a large area and contain a
-    huge number of features.
-    """
-    raise NotImplementedError()
-  def RecordRoute(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A client-to-server streaming RPC.
-
-    Accepts a stream of Points on a route being traversed, returning a
-    RouteSummary when traversal is completed.
-    """
-    raise NotImplementedError()
-  RecordRoute.future = None
-  def RouteChat(self, request_iterator, timeout, metadata=None, with_call=False, protocol_options=None):
-    """A Bidirectional streaming RPC.
-
-    Accepts a stream of RouteNotes sent while a route is being traversed,
-    while receiving other RouteNotes (e.g. from other users).
-    """
-    raise NotImplementedError()
-
-
-def beta_create_RouteGuide_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
-  request_deserializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Point.FromString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.FromString,
-    ('routeguide.RouteGuide', 'RecordRoute'): Point.FromString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
-  }
-  response_serializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Feature.SerializeToString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Feature.SerializeToString,
-    ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.SerializeToString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
-  }
-  method_implementations = {
-    ('routeguide.RouteGuide', 'GetFeature'): face_utilities.unary_unary_inline(servicer.GetFeature),
-    ('routeguide.RouteGuide', 'ListFeatures'): face_utilities.unary_stream_inline(servicer.ListFeatures),
-    ('routeguide.RouteGuide', 'RecordRoute'): face_utilities.stream_unary_inline(servicer.RecordRoute),
-    ('routeguide.RouteGuide', 'RouteChat'): face_utilities.stream_stream_inline(servicer.RouteChat),
-  }
-  server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
-  return beta_implementations.server(method_implementations, options=server_options)
-
-
-def beta_create_RouteGuide_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
-  request_serializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Point.SerializeToString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.SerializeToString,
-    ('routeguide.RouteGuide', 'RecordRoute'): Point.SerializeToString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
-  }
-  response_deserializers = {
-    ('routeguide.RouteGuide', 'GetFeature'): Feature.FromString,
-    ('routeguide.RouteGuide', 'ListFeatures'): Feature.FromString,
-    ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.FromString,
-    ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
-  }
-  cardinalities = {
-    'GetFeature': cardinality.Cardinality.UNARY_UNARY,
-    'ListFeatures': cardinality.Cardinality.UNARY_STREAM,
-    'RecordRoute': cardinality.Cardinality.STREAM_UNARY,
-    'RouteChat': cardinality.Cardinality.STREAM_STREAM,
-  }
-  stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
-  return beta_implementations.dynamic_stub(channel, 'routeguide.RouteGuide', cardinalities, options=stub_options)
+    It is recommended to use the GA API (classes and functions in this
+    file not marked beta) for all further purposes. This function was
+    generated only to ease transition from grpcio<0.15.0 to grpcio>=0.15.0"""
+    request_serializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Point.SerializeToString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Rectangle.SerializeToString,
+      ('routeguide.RouteGuide', 'RecordRoute'): Point.SerializeToString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.SerializeToString,
+    }
+    response_deserializers = {
+      ('routeguide.RouteGuide', 'GetFeature'): Feature.FromString,
+      ('routeguide.RouteGuide', 'ListFeatures'): Feature.FromString,
+      ('routeguide.RouteGuide', 'RecordRoute'): RouteSummary.FromString,
+      ('routeguide.RouteGuide', 'RouteChat'): RouteNote.FromString,
+    }
+    cardinalities = {
+      'GetFeature': cardinality.Cardinality.UNARY_UNARY,
+      'ListFeatures': cardinality.Cardinality.UNARY_STREAM,
+      'RecordRoute': cardinality.Cardinality.STREAM_UNARY,
+      'RouteChat': cardinality.Cardinality.STREAM_STREAM,
+    }
+    stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
+    return beta_implementations.dynamic_stub(channel, 'routeguide.RouteGuide', cardinalities, options=stub_options)
+except ImportError:
+  pass
 # @@protoc_insertion_point(module_scope)
diff --git a/examples/python/route_guide/route_guide_pb2_grpc.py b/examples/python/route_guide/route_guide_pb2_grpc.py
new file mode 100644
index 0000000..27b24c7
--- /dev/null
+++ b/examples/python/route_guide/route_guide_pb2_grpc.py
@@ -0,0 +1,114 @@
+import grpc
+from grpc.framework.common import cardinality
+from grpc.framework.interfaces.face import utilities as face_utilities
+
+import route_guide_pb2 as route__guide__pb2
+
+
+class RouteGuideStub(object):
+  """Interface exported by the server.
+  """
+
+  def __init__(self, channel):
+    """Constructor.
+
+    Args:
+      channel: A grpc.Channel.
+    """
+    self.GetFeature = channel.unary_unary(
+        '/routeguide.RouteGuide/GetFeature',
+        request_serializer=route__guide__pb2.Point.SerializeToString,
+        response_deserializer=route__guide__pb2.Feature.FromString,
+        )
+    self.ListFeatures = channel.unary_stream(
+        '/routeguide.RouteGuide/ListFeatures',
+        request_serializer=route__guide__pb2.Rectangle.SerializeToString,
+        response_deserializer=route__guide__pb2.Feature.FromString,
+        )
+    self.RecordRoute = channel.stream_unary(
+        '/routeguide.RouteGuide/RecordRoute',
+        request_serializer=route__guide__pb2.Point.SerializeToString,
+        response_deserializer=route__guide__pb2.RouteSummary.FromString,
+        )
+    self.RouteChat = channel.stream_stream(
+        '/routeguide.RouteGuide/RouteChat',
+        request_serializer=route__guide__pb2.RouteNote.SerializeToString,
+        response_deserializer=route__guide__pb2.RouteNote.FromString,
+        )
+
+
+class RouteGuideServicer(object):
+  """Interface exported by the server.
+  """
+
+  def GetFeature(self, request, context):
+    """A simple RPC.
+
+    Obtains the feature at a given position.
+
+    A feature with an empty name is returned if there's no feature at the given
+    position.
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+  def ListFeatures(self, request, context):
+    """A server-to-client streaming RPC.
+
+    Obtains the Features available within the given Rectangle.  Results are
+    streamed rather than returned at once (e.g. in a response message with a
+    repeated field), as the rectangle may cover a large area and contain a
+    huge number of features.
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+  def RecordRoute(self, request_iterator, context):
+    """A client-to-server streaming RPC.
+
+    Accepts a stream of Points on a route being traversed, returning a
+    RouteSummary when traversal is completed.
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+  def RouteChat(self, request_iterator, context):
+    """A Bidirectional streaming RPC.
+
+    Accepts a stream of RouteNotes sent while a route is being traversed,
+    while receiving other RouteNotes (e.g. from other users).
+    """
+    context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+    context.set_details('Method not implemented!')
+    raise NotImplementedError('Method not implemented!')
+
+
+def add_RouteGuideServicer_to_server(servicer, server):
+  rpc_method_handlers = {
+      'GetFeature': grpc.unary_unary_rpc_method_handler(
+          servicer.GetFeature,
+          request_deserializer=route__guide__pb2.Point.FromString,
+          response_serializer=route__guide__pb2.Feature.SerializeToString,
+      ),
+      'ListFeatures': grpc.unary_stream_rpc_method_handler(
+          servicer.ListFeatures,
+          request_deserializer=route__guide__pb2.Rectangle.FromString,
+          response_serializer=route__guide__pb2.Feature.SerializeToString,
+      ),
+      'RecordRoute': grpc.stream_unary_rpc_method_handler(
+          servicer.RecordRoute,
+          request_deserializer=route__guide__pb2.Point.FromString,
+          response_serializer=route__guide__pb2.RouteSummary.SerializeToString,
+      ),
+      'RouteChat': grpc.stream_stream_rpc_method_handler(
+          servicer.RouteChat,
+          request_deserializer=route__guide__pb2.RouteNote.FromString,
+          response_serializer=route__guide__pb2.RouteNote.SerializeToString,
+      ),
+  }
+  generic_handler = grpc.method_handlers_generic_handler(
+      'routeguide.RouteGuide', rpc_method_handlers)
+  server.add_generic_rpc_handlers((generic_handler,))
diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py
index 3ffe678..bf49217 100644
--- a/examples/python/route_guide/route_guide_server.py
+++ b/examples/python/route_guide/route_guide_server.py
@@ -36,6 +36,7 @@
 import grpc
 
 import route_guide_pb2
+import route_guide_pb2_grpc
 import route_guide_resources
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
@@ -68,7 +69,7 @@
   R = 6371000; # metres
   return R * c;
 
-class RouteGuideServicer(route_guide_pb2.RouteGuideServicer):
+class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
   """Provides methods that implement functionality of route guide server."""
 
   def __init__(self):
@@ -125,7 +126,7 @@
 
 def serve():
   server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
-  route_guide_pb2.add_RouteGuideServicer_to_server(
+  route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
       RouteGuideServicer(), server)
   server.add_insecure_port('[::]:50051')
   server.start()
diff --git a/examples/python/route_guide/run_codegen.py b/examples/python/route_guide/run_codegen.py
index c7c6008..3751e01 100644
--- a/examples/python/route_guide/run_codegen.py
+++ b/examples/python/route_guide/run_codegen.py
@@ -29,7 +29,7 @@
 
 """Runs protoc with the gRPC plugin to generate messages and gRPC stubs."""
 
-from grpc.tools import protoc
+from grpc_tools import protoc
 
 protoc.main(
     (
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 04f7211..e56eedd 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -35,7 +35,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.0.1'
+  version = '1.0.2'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'http://www.grpc.io'
@@ -44,7 +44,9 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "v#{version}",
+    # TODO(mxyan): Change back to "v#{version}" for next release
+    #:tag => "v#{version}",
+    :tag => "objective-c-v#{version}",
     # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
     :submodules => true,
   }
@@ -165,6 +167,7 @@
                       'include/grpc/impl/codegen/byte_buffer_reader.h',
                       'include/grpc/impl/codegen/compression_types.h',
                       'include/grpc/impl/codegen/connectivity_state.h',
+                      'include/grpc/impl/codegen/exec_ctx_fwd.h',
                       'include/grpc/impl/codegen/grpc_types.h',
                       'include/grpc/impl/codegen/propagation_bits.h',
                       'include/grpc/impl/codegen/status.h',
@@ -253,6 +256,8 @@
                       'src/core/lib/channel/context.h',
                       'src/core/lib/channel/deadline_filter.h',
                       'src/core/lib/channel/handshaker.h',
+                      'src/core/lib/channel/handshaker_factory.h',
+                      'src/core/lib/channel/handshaker_registry.h',
                       'src/core/lib/channel/http_client_filter.h',
                       'src/core/lib/channel/http_server_filter.h',
                       'src/core/lib/channel/message_size_filter.h',
@@ -319,6 +324,7 @@
                       'src/core/lib/json/json_reader.h',
                       'src/core/lib/json/json_writer.h',
                       'src/core/lib/slice/percent_encoding.h',
+                      'src/core/lib/slice/slice_internal.h',
                       'src/core/lib/slice/slice_string_helpers.h',
                       'src/core/lib/surface/api_trace.h',
                       'src/core/lib/surface/call.h',
@@ -432,6 +438,8 @@
                       'src/core/lib/channel/connected_channel.c',
                       'src/core/lib/channel/deadline_filter.c',
                       'src/core/lib/channel/handshaker.c',
+                      'src/core/lib/channel/handshaker_factory.c',
+                      'src/core/lib/channel/handshaker_registry.c',
                       'src/core/lib/channel/http_client_filter.c',
                       'src/core/lib/channel/http_server_filter.c',
                       'src/core/lib/channel/message_size_filter.c',
@@ -660,6 +668,8 @@
                               'src/core/lib/channel/context.h',
                               'src/core/lib/channel/deadline_filter.h',
                               'src/core/lib/channel/handshaker.h',
+                              'src/core/lib/channel/handshaker_factory.h',
+                              'src/core/lib/channel/handshaker_registry.h',
                               'src/core/lib/channel/http_client_filter.h',
                               'src/core/lib/channel/http_server_filter.h',
                               'src/core/lib/channel/message_size_filter.h',
@@ -726,6 +736,7 @@
                               'src/core/lib/json/json_reader.h',
                               'src/core/lib/json/json_writer.h',
                               'src/core/lib/slice/percent_encoding.h',
+                              'src/core/lib/slice/slice_internal.h',
                               'src/core/lib/slice/slice_string_helpers.h',
                               'src/core/lib/surface/api_trace.h',
                               'src/core/lib/surface/call.h',
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index 61d4b62..62eaa2a 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -30,7 +30,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.0.1'
+  version = '1.0.2'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'http://www.grpc.io'
@@ -39,7 +39,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "v#{version}",
+    :tag => "objective-c-v#{version}",
   }
 
   s.ios.deployment_target = '7.1'
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index d59385c..2e8fffd 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -30,7 +30,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.0.1'
+  version = '1.0.2'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'http://www.grpc.io'
@@ -39,7 +39,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "v#{version}",
+    :tag => "objective-c-v#{version}",
   }
 
   s.ios.deployment_target = '7.1'
diff --git a/gRPC.podspec b/gRPC.podspec
index 76410b1..e8b7709 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -30,7 +30,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.0.1'
+  version = '1.0.2'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'http://www.grpc.io'
@@ -39,7 +39,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "v#{version}",
+    :tag => "objective-c-v#{version}",
   }
 
   s.ios.deployment_target = '7.1'
diff --git a/grpc.gemspec b/grpc.gemspec
index 6019b97..d1dcb1d 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -27,7 +27,7 @@
   s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
-  s.add_dependency 'google-protobuf', '~> 3.0.2'
+  s.add_dependency 'google-protobuf', '~> 3.1.0'
   s.add_dependency 'googleauth',      '~> 0.5.1'
 
   s.add_development_dependency 'bundler',            '~> 1.9'
@@ -148,6 +148,7 @@
   s.files += %w( include/grpc/impl/codegen/byte_buffer_reader.h )
   s.files += %w( include/grpc/impl/codegen/compression_types.h )
   s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
+  s.files += %w( include/grpc/impl/codegen/exec_ctx_fwd.h )
   s.files += %w( include/grpc/impl/codegen/grpc_types.h )
   s.files += %w( include/grpc/impl/codegen/propagation_bits.h )
   s.files += %w( include/grpc/impl/codegen/status.h )
@@ -172,6 +173,8 @@
   s.files += %w( src/core/lib/channel/context.h )
   s.files += %w( src/core/lib/channel/deadline_filter.h )
   s.files += %w( src/core/lib/channel/handshaker.h )
+  s.files += %w( src/core/lib/channel/handshaker_factory.h )
+  s.files += %w( src/core/lib/channel/handshaker_registry.h )
   s.files += %w( src/core/lib/channel/http_client_filter.h )
   s.files += %w( src/core/lib/channel/http_server_filter.h )
   s.files += %w( src/core/lib/channel/message_size_filter.h )
@@ -238,6 +241,7 @@
   s.files += %w( src/core/lib/json/json_reader.h )
   s.files += %w( src/core/lib/json/json_writer.h )
   s.files += %w( src/core/lib/slice/percent_encoding.h )
+  s.files += %w( src/core/lib/slice/slice_internal.h )
   s.files += %w( src/core/lib/slice/slice_string_helpers.h )
   s.files += %w( src/core/lib/surface/api_trace.h )
   s.files += %w( src/core/lib/surface/call.h )
@@ -351,6 +355,8 @@
   s.files += %w( src/core/lib/channel/connected_channel.c )
   s.files += %w( src/core/lib/channel/deadline_filter.c )
   s.files += %w( src/core/lib/channel/handshaker.c )
+  s.files += %w( src/core/lib/channel/handshaker_factory.c )
+  s.files += %w( src/core/lib/channel/handshaker_registry.c )
   s.files += %w( src/core/lib/channel/http_client_filter.c )
   s.files += %w( src/core/lib/channel/http_server_filter.c )
   s.files += %w( src/core/lib/channel/message_size_filter.c )
diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h
index 36d65d6..daecfea 100644
--- a/include/grpc++/grpc++.h
+++ b/include/grpc++/grpc++.h
@@ -44,6 +44,10 @@
 /// peer, compression settings, authentication, etc.
 /// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
 ///
+/// Streaming calls are handled with the streaming classes in
+/// \ref sync_stream.h and
+/// \ref async_stream.h.
+///
 /// Refer to the
 /// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp)
 /// for code putting these pieces into play.
diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h
index 944f2c3..03cecdc 100644
--- a/include/grpc++/impl/codegen/completion_queue.h
+++ b/include/grpc++/impl/codegen/completion_queue.h
@@ -94,8 +94,10 @@
 
 extern CoreCodegenInterface* g_core_codegen_interface;
 
-/// A thin wrapper around \a grpc_completion_queue (see / \a
-/// src/core/surface/completion_queue.h).
+/// A thin wrapper around \ref grpc_completion_queue (see \ref
+/// src/core/lib/surface/completion_queue.h).
+/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
+/// performance servers.
 class CompletionQueue : private GrpcLibraryCodegen {
  public:
   /// Default constructor. Implicitly creates a \a grpc_completion_queue
diff --git a/include/grpc++/resource_quota.h b/include/grpc++/resource_quota.h
index 75e04d4..68a5146 100644
--- a/include/grpc++/resource_quota.h
+++ b/include/grpc++/resource_quota.h
@@ -37,6 +37,7 @@
 struct grpc_resource_quota;
 
 #include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/grpc_library.h>
 
 namespace grpc {
 
@@ -44,7 +45,7 @@
 /// A ResourceQuota can be attached to a server (via ServerBuilder), or a client
 /// channel (via ChannelArguments). gRPC will attempt to keep memory used by
 /// all attached entities below the ResourceQuota bound.
-class ResourceQuota final {
+class ResourceQuota final : private GrpcLibraryCodegen {
  public:
   explicit ResourceQuota(const grpc::string& name);
   ResourceQuota();
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index 9252c6a..2ac2f0a 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -187,7 +187,7 @@
 
   struct SyncServerSettings {
     SyncServerSettings()
-        : num_cqs(GPR_MAX(gpr_cpu_num_cores(), 4)),
+        : num_cqs(1),
           min_pollers(1),
           max_pollers(INT_MAX),
           cq_timeout_msec(1000) {}
diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h
index 571ab5d..d43f7c6 100644
--- a/include/grpc++/support/channel_arguments.h
+++ b/include/grpc++/support/channel_arguments.h
@@ -127,7 +127,7 @@
   /// Default pointer argument operations.
   struct PointerVtableMembers {
     static void* Copy(void* in) { return in; }
-    static void Destroy(void* in) {}
+    static void Destroy(grpc_exec_ctx* exec_ctx, void* in) {}
     static int Compare(void* a, void* b) {
       if (a < b) return -1;
       if (a > b) return 1;
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 5e48621..898f4d5 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -202,9 +202,15 @@
     completion of type 'tag' to the completion queue bound to the call.
     The order of ops specified in the batch has no significance.
     Only one operation of each type can be active at once in any given
-    batch. You must call grpc_completion_queue_next or
-    grpc_completion_queue_pluck on the completion queue associated with 'call'
-    for work to be performed.
+    batch.
+    If a call to grpc_call_start_batch returns GRPC_CALL_OK you must call
+    grpc_completion_queue_next or grpc_completion_queue_pluck on the completion
+    queue associated with 'call' for work to be performed. If a call to
+    grpc_call_start_batch returns any value other than GRPC_CALL_OK it is
+    guaranteed that no state associated with 'call' is changed and it is not
+    appropriate to call grpc_completion_queue_next or
+    grpc_completion_queue_pluck consequent to the failed grpc_call_start_batch
+    call.
     THREAD SAFETY: access to grpc_call_start_batch in multi-threaded environment
     needs to be synchronized. As an optimization, you may synchronize batches
     containing just send operations independently from batches containing just
diff --git a/include/grpc/impl/codegen/exec_ctx_fwd.h b/include/grpc/impl/codegen/exec_ctx_fwd.h
new file mode 100644
index 0000000..32edced
--- /dev/null
+++ b/include/grpc/impl/codegen/exec_ctx_fwd.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_EXEC_CTX_FWD_H
+#define GRPC_IMPL_CODEGEN_EXEC_CTX_FWD_H
+
+/* forward declaration for exec_ctx.h */
+struct grpc_exec_ctx;
+typedef struct grpc_exec_ctx grpc_exec_ctx;
+
+#endif /* GRPC_IMPL_CODEGEN_EXEC_CTX_FWD_H */
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index da1bd9d..42825b6 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -34,10 +34,10 @@
 #ifndef GRPC_IMPL_CODEGEN_GRPC_TYPES_H
 #define GRPC_IMPL_CODEGEN_GRPC_TYPES_H
 
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/exec_ctx_fwd.h>
 #include <grpc/impl/codegen/gpr_types.h>
 #include <grpc/impl/codegen/slice.h>
-
-#include <grpc/impl/codegen/compression_types.h>
 #include <grpc/impl/codegen/status.h>
 
 #include <stddef.h>
@@ -96,7 +96,7 @@
 
 typedef struct grpc_arg_pointer_vtable {
   void *(*copy)(void *p);
-  void (*destroy)(void *p);
+  void (*destroy)(grpc_exec_ctx *exec_ctx, void *p);
   int (*cmp)(void *p, void *q);
 } grpc_arg_pointer_vtable;
 
@@ -206,18 +206,12 @@
 /** If non-zero, allow the use of SO_REUSEPORT if it's available (default 1) */
 #define GRPC_ARG_ALLOW_REUSEPORT "grpc.so_reuseport"
 /** If non-zero, a pointer to a buffer pool (use grpc_resource_quota_arg_vtable
-   to fetch an appropriate pointer arg vtable */
+   to fetch an appropriate pointer arg vtable) */
 #define GRPC_ARG_RESOURCE_QUOTA "grpc.resource_quota"
-/** Service config data, to be passed to subchannels.
-    Not intended for external use. */
+/** Service config data in JSON form. Not intended for use outside of tests. */
 #define GRPC_ARG_SERVICE_CONFIG "grpc.service_config"
 /** LB policy name. */
 #define GRPC_ARG_LB_POLICY_NAME "grpc.lb_policy_name"
-/** Server name. Not intended for external use. */
-#define GRPC_ARG_SERVER_NAME "grpc.server_name"
-/** Resolved addresses in a form used by the LB policy.
-    Not intended for external use. */
-#define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses"
 /** The grpc_socket_mutator instance that set the socket options. A pointer. */
 #define GRPC_ARG_SOCKET_MUTATOR "grpc.socket_mutator"
 /** \} */
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index cd989d6..4633fa1 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -361,7 +361,7 @@
 #define GPR_MAX_ALIGNMENT 16
 
 #ifndef GRPC_MUST_USE_RESULT
-#ifdef __GNUC__
+#if defined(__GNUC__) && !defined(__MINGW32__)
 #define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))
 #else
 #define GRPC_MUST_USE_RESULT
diff --git a/include/grpc/impl/codegen/slice.h b/include/grpc/impl/codegen/slice.h
index 774ba0e..4d4a86f 100644
--- a/include/grpc/impl/codegen/slice.h
+++ b/include/grpc/impl/codegen/slice.h
@@ -37,6 +37,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <grpc/impl/codegen/exec_ctx_fwd.h>
+
 /* Slice API
 
    A slice represents a contiguous reference counted array of bytes.
@@ -57,7 +59,7 @@
    grpc_slice_new, or grpc_slice_new_with_len instead. */
 typedef struct grpc_slice_refcount {
   void (*ref)(void *);
-  void (*unref)(void *);
+  void (*unref)(grpc_exec_ctx *exec_ctx, void *);
 } grpc_slice_refcount;
 
 #define GRPC_SLICE_INLINED_SIZE (sizeof(size_t) + sizeof(uint8_t *) - 1)
diff --git a/include/grpc/support/log_windows.h b/include/grpc/support/log_windows.h
index 12bf8cc..943a8e9 100644
--- a/include/grpc/support/log_windows.h
+++ b/include/grpc/support/log_windows.h
@@ -34,6 +34,8 @@
 #ifndef GRPC_SUPPORT_LOG_WINDOWS_H
 #define GRPC_SUPPORT_LOG_WINDOWS_H
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/package.json b/package.json
index 5506e9b..375db74 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
   "scripts": {
     "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js --exclude-path=src/node/.jshintignore",
     "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
+    "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell",
     "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
     "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
     "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build"
@@ -38,6 +39,7 @@
   "devDependencies": {
     "async": "^2.0.1",
     "body-parser": "^1.15.2",
+    "electron-mocha": "^3.1.1",
     "express": "^4.14.0",
     "google-auth-library": "^0.9.2",
     "google-protobuf": "^3.0.0",
@@ -50,7 +52,7 @@
     "poisson-process": "^0.2.1"
   },
   "engines": {
-    "node": ">=0.12.0"
+    "node": ">=1.1.0"
   },
   "binary": {
     "module_name": "grpc_node",
diff --git a/package.xml b/package.xml
index 6166881..4df1525 100644
--- a/package.xml
+++ b/package.xml
@@ -156,6 +156,7 @@
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer_reader.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/compression_types.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/connectivity_state.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/exec_ctx_fwd.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/grpc_types.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/propagation_bits.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/status.h" role="src" />
@@ -180,6 +181,8 @@
     <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/deadline_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.h" role="src" />
@@ -246,6 +249,7 @@
     <file baseinstalldir="/" name="src/core/lib/json/json_reader.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/json/json_writer.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/percent_encoding.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />
@@ -359,6 +363,8 @@
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/deadline_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/handshaker.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_client_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/http_server_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/message_size_filter.c" role="src" />
diff --git a/setup.py b/setup.py
index 559a75f..ab21743 100644
--- a/setup.py
+++ b/setup.py
@@ -218,15 +218,18 @@
     'six>=1.10',
   ) if ENABLE_DOCUMENTATION_BUILD else ()
 
-if BUILD_WITH_CYTHON:
-  sys.stderr.write(
-    "You requested a Cython build via GRPC_PYTHON_BUILD_WITH_CYTHON, "
-    "but do not have Cython installed. We won't stop you from using "
-    "other commands, but the extension files will fail to build.\n")
-elif need_cython:
-  sys.stderr.write(
-      'We could not find Cython. Setup may take 10-20 minutes.\n')
-  SETUP_REQUIRES += ('cython>=0.23',)
+try:
+  import Cython
+except ImportError:
+  if BUILD_WITH_CYTHON:
+    sys.stderr.write(
+      "You requested a Cython build via GRPC_PYTHON_BUILD_WITH_CYTHON, "
+      "but do not have Cython installed. We won't stop you from using "
+      "other commands, but the extension files will fail to build.\n")
+  elif need_cython:
+    sys.stderr.write(
+        'We could not find Cython. Setup may take 10-20 minutes.\n')
+    SETUP_REQUIRES += ('cython>=0.23',)
 
 COMMAND_CLASS = {
     'doc': commands.SphinxDocumentation,
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index a3af258..cc7a7a9 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -68,13 +68,13 @@
 // Currently, we cannot easily reuse the functionality as
 // google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
 // TODO(jtattermusch): reuse the functionality from google/protobuf.
-void GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer *printer,
+bool GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer *printer,
                                 grpc::protobuf::SourceLocation location) {
   grpc::string comments = location.leading_comments.empty()
                               ? location.trailing_comments
                               : location.leading_comments;
   if (comments.empty()) {
-    return;
+    return false;
   }
   // XML escaping... no need for apostrophes etc as the whole text is going to
   // be a child
@@ -107,18 +107,84 @@
         printer->Print("///\n");
       }
       last_was_empty = false;
-      printer->Print("/// $line$\n", "line", *it);
+      printer->Print("///$line$\n", "line", *it);
     }
   }
   printer->Print("/// </summary>\n");
+  return true;
 }
 
 template <typename DescriptorType>
-void GenerateDocCommentBody(grpc::protobuf::io::Printer *printer,
+bool GenerateDocCommentBody(grpc::protobuf::io::Printer *printer,
                             const DescriptorType *descriptor) {
   grpc::protobuf::SourceLocation location;
-  if (descriptor->GetSourceLocation(&location)) {
-    GenerateDocCommentBodyImpl(printer, location);
+  if (!descriptor->GetSourceLocation(&location)) {
+    return false;
+  }
+  return GenerateDocCommentBodyImpl(printer, location);
+}
+
+void GenerateDocCommentServerMethod(grpc::protobuf::io::Printer *printer,
+                                    const MethodDescriptor *method) {
+  if (GenerateDocCommentBody(printer, method)) {
+    if (method->client_streaming()) {
+      printer->Print(
+          "/// <param name=\"requestStream\">Used for reading requests from "
+          "the client.</param>\n");
+    } else {
+      printer->Print(
+          "/// <param name=\"request\">The request received from the "
+          "client.</param>\n");
+    }
+    if (method->server_streaming()) {
+      printer->Print(
+          "/// <param name=\"responseStream\">Used for sending responses back "
+          "to the client.</param>\n");
+    }
+    printer->Print(
+        "/// <param name=\"context\">The context of the server-side call "
+        "handler being invoked.</param>\n");
+    if (method->server_streaming()) {
+      printer->Print(
+          "/// <returns>A task indicating completion of the "
+          "handler.</returns>\n");
+    } else {
+      printer->Print(
+          "/// <returns>The response to send back to the client (wrapped by a "
+          "task).</returns>\n");
+    }
+  }
+}
+
+void GenerateDocCommentClientMethod(grpc::protobuf::io::Printer *printer,
+                                    const MethodDescriptor *method,
+                                    bool is_sync, bool use_call_options) {
+  if (GenerateDocCommentBody(printer, method)) {
+    if (!method->client_streaming()) {
+      printer->Print(
+          "/// <param name=\"request\">The request to send to the "
+          "server.</param>\n");
+    }
+    if (!use_call_options) {
+      printer->Print(
+          "/// <param name=\"headers\">The initial metadata to send with the "
+          "call. This parameter is optional.</param>\n");
+      printer->Print(
+          "/// <param name=\"deadline\">An optional deadline for the call. The "
+          "call will be cancelled if deadline is hit.</param>\n");
+      printer->Print(
+          "/// <param name=\"cancellationToken\">An optional token for "
+          "canceling the call.</param>\n");
+    } else {
+      printer->Print(
+          "/// <param name=\"options\">The options for the call.</param>\n");
+    }
+    if (is_sync) {
+      printer->Print(
+          "/// <returns>The response received from the server.</returns>\n");
+    } else {
+      printer->Print("/// <returns>The call object.</returns>\n");
+    }
   }
 }
 
@@ -319,7 +385,7 @@
   out->Indent();
   for (int i = 0; i < service->method_count(); i++) {
     const MethodDescriptor *method = service->method(i);
-    GenerateDocCommentBody(out, method);
+    GenerateDocCommentServerMethod(out, method);
     out->Print(
         "public virtual $returntype$ "
         "$methodname$($request$$response_stream_maybe$, "
@@ -393,7 +459,7 @@
 
     if (method_type == METHODTYPE_NO_STREAMING) {
       // unary calls have an extra synchronous stub method
-      GenerateDocCommentBody(out, method);
+      GenerateDocCommentClientMethod(out, method, true, false);
       out->Print(
           "public virtual $response$ $methodname$($request$ request, Metadata "
           "headers = null, DateTime? deadline = null, CancellationToken "
@@ -411,7 +477,7 @@
       out->Print("}\n");
 
       // overload taking CallOptions as a param
-      GenerateDocCommentBody(out, method);
+      GenerateDocCommentClientMethod(out, method, true, true);
       out->Print(
           "public virtual $response$ $methodname$($request$ request, "
           "CallOptions options)\n",
@@ -432,7 +498,7 @@
     if (method_type == METHODTYPE_NO_STREAMING) {
       method_name += "Async";  // prevent name clash with synchronous method.
     }
-    GenerateDocCommentBody(out, method);
+    GenerateDocCommentClientMethod(out, method, false, false);
     out->Print(
         "public virtual $returntype$ $methodname$($request_maybe$Metadata "
         "headers = null, DateTime? deadline = null, CancellationToken "
@@ -452,7 +518,7 @@
     out->Print("}\n");
 
     // overload taking CallOptions as a param
-    GenerateDocCommentBody(out, method);
+    GenerateDocCommentClientMethod(out, method, false, true);
     out->Print(
         "public virtual $returntype$ $methodname$($request_maybe$CallOptions "
         "options)\n",
@@ -518,6 +584,9 @@
       "/// <summary>Creates service definition that can be registered with a "
       "server</summary>\n");
   out->Print(
+      "/// <param name=\"serviceImpl\">An object implementing the server-side"
+      " handling logic.</param>\n");
+  out->Print(
       "public static ServerServiceDefinition BindService($implclass$ "
       "serviceImpl)\n",
       "implclass", GetServerClassName(service));
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index b0a6009..4841da8 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -40,6 +40,7 @@
 #include <map>
 #include <memory>
 #include <ostream>
+#include <set>
 #include <sstream>
 #include <tuple>
 #include <vector>
@@ -64,7 +65,9 @@
 using std::map;
 using std::pair;
 using std::replace;
+using std::tuple;
 using std::vector;
+using std::set;
 
 namespace grpc_python_generator {
 
@@ -73,6 +76,8 @@
 typedef vector<const Descriptor*> DescriptorVector;
 typedef map<grpc::string, grpc::string> StringMap;
 typedef vector<grpc::string> StringVector;
+typedef tuple<grpc::string, grpc::string> StringPair;
+typedef set<StringPair> StringPairSet;
 
 // Provides RAII indentation handling. Use as:
 // {
@@ -651,6 +656,7 @@
       "face_utilities\n");
   if (generate_in_pb2_grpc) {
     out->Print("\n");
+    StringPairSet imports_set;
     for (int i = 0; i < file->service_count(); ++i) {
       const ServiceDescriptor* service = file->service(i);
       for (int j = 0; j < service->method_count(); ++j) {
@@ -662,11 +668,15 @@
           grpc::string type_file_name = type->file()->name();
           grpc::string module_name = ModuleName(type_file_name);
           grpc::string module_alias = ModuleAlias(type_file_name);
-          out->Print("import $ModuleName$ as $ModuleAlias$\n", "ModuleName",
-                     module_name, "ModuleAlias", module_alias);
+          imports_set.insert(std::make_tuple(module_name, module_alias));
         }
       }
     }
+    for (StringPairSet::iterator it = imports_set.begin();
+         it != imports_set.end(); ++it) {
+      out->Print("import $ModuleName$ as $ModuleAlias$\n", "ModuleName",
+                 std::get<0>(*it), "ModuleAlias", std::get<1>(*it));
+    }
   }
   return true;
 }
@@ -714,6 +724,9 @@
     out = &out_printer;
 
     if (generate_in_pb2_grpc) {
+      out->Print(
+          "# Generated by the gRPC Python protocol compiler plugin. "
+          "DO NOT EDIT!\n");
       if (!PrintPreamble()) {
         return make_pair(false, "");
       }
diff --git a/src/core/ext/README.md b/src/core/ext/README.md
new file mode 100644
index 0000000..0812b20
--- /dev/null
+++ b/src/core/ext/README.md
@@ -0,0 +1,5 @@
+Optional plugins for gRPC Core: Modules in this directory extend gRPC Core in
+useful ways. All optional code belongs here.
+
+NOTE: The movement of code between lib and ext is an ongoing effort, so this
+directory currently contains too much of the core library.
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index 397dbc4..8e4d473 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -154,7 +154,8 @@
   memset(d, 0, sizeof(*d));
   d->start_ts = args->start_time;
   /* TODO(hongyu): call census_tracing_start_op here. */
-  grpc_closure_init(&d->finish_recv, server_on_done_recv, elem);
+  grpc_closure_init(&d->finish_recv, server_on_done_recv, elem,
+                    grpc_schedule_on_exec_ctx);
   return GRPC_ERROR_NONE;
 }
 
@@ -167,11 +168,12 @@
   /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
 }
 
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(chand != NULL);
+  return GRPC_ERROR_NONE;
 }
 
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/census/grpc_plugin.c b/src/core/ext/census/grpc_plugin.c
index e43ceaf..c9fe453 100644
--- a/src/core/ext/census/grpc_plugin.c
+++ b/src/core/ext/census/grpc_plugin.c
@@ -51,7 +51,8 @@
   return census_enabled();
 }
 
-static bool maybe_add_census_filter(grpc_channel_stack_builder *builder,
+static bool maybe_add_census_filter(grpc_exec_ctx *exec_ctx,
+                                    grpc_channel_stack_builder *builder,
                                     void *arg) {
   const grpc_channel_args *args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
diff --git a/src/core/ext/census/tracing.c b/src/core/ext/census/tracing.c
index 8f0e122..3b5d6da 100644
--- a/src/core/ext/census/tracing.c
+++ b/src/core/ext/census/tracing.c
@@ -31,19 +31,15 @@
  *
  */
 
-//#include "src/core/ext/census/tracing.h"
-
 #include <grpc/census.h>
 
 /* TODO(aveitch): These are all placeholder implementations. */
 
-// int census_trace_mask(const census_context *context) {
-//   return CENSUS_TRACE_MASK_NONE;
-// }
+int census_trace_mask(const census_context *context) {
+  return CENSUS_TRACE_MASK_NONE;
+}
 
-// void census_set_trace_mask(int trace_mask) {}
+void census_set_trace_mask(int trace_mask) {}
 
-// void census_trace_print(census_context *context, uint32_t type,
-//                         const char *buffer, size_t n) {}
-
-// void SetTracerParams(const Params& params);
+void census_trace_print(census_context *context, uint32_t type,
+                        const char *buffer, size_t n) {}
diff --git a/src/core/ext/client_channel/channel_connectivity.c b/src/core/ext/client_channel/channel_connectivity.c
index 9797e66..dd70bc2 100644
--- a/src/core/ext/client_channel/channel_connectivity.c
+++ b/src/core/ext/client_channel/channel_connectivity.c
@@ -76,6 +76,7 @@
   gpr_mu mu;
   callback_phase phase;
   grpc_closure on_complete;
+  grpc_closure on_timeout;
   grpc_timer alarm;
   grpc_connectivity_state state;
   grpc_completion_queue *cq;
@@ -198,7 +199,10 @@
   grpc_cq_begin_op(cq, tag);
 
   gpr_mu_init(&w->mu);
-  grpc_closure_init(&w->on_complete, watch_complete, w);
+  grpc_closure_init(&w->on_complete, watch_complete, w,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&w->on_timeout, timeout_complete, w,
+                    grpc_schedule_on_exec_ctx);
   w->phase = WAITING;
   w->state = last_observed_state;
   w->cq = cq;
@@ -207,7 +211,7 @@
 
   grpc_timer_init(&exec_ctx, &w->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
 
   if (client_channel_elem->filter == &grpc_client_channel_filter) {
     GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 1fcff43..2f25fef 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -44,6 +44,7 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/ext/client_channel/lb_policy_registry.h"
+#include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/client_channel/subchannel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
@@ -82,8 +83,12 @@
   return new_value;
 }
 
+static void method_parameters_free(grpc_exec_ctx *exec_ctx, void *p) {
+  gpr_free(p);
+}
+
 static const grpc_mdstr_hash_table_vtable method_parameters_vtable = {
-    gpr_free, method_parameters_copy};
+    method_parameters_free, method_parameters_copy};
 
 static void *method_parameters_create_from_json(const grpc_json *json) {
   wait_for_ready_value wait_for_ready = WAIT_FOR_READY_UNSET;
@@ -248,7 +253,8 @@
   GRPC_CHANNEL_STACK_REF(chand->owning_stack, "watch_lb_policy");
 
   w->chand = chand;
-  grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w);
+  grpc_closure_init(&w->on_changed, on_lb_policy_state_changed, w,
+                    grpc_schedule_on_exec_ctx);
   w->state = current_state;
   w->lb_policy = lb_policy;
   grpc_lb_policy_notify_on_state_change(exec_ctx, lb_policy, &w->state,
@@ -326,7 +332,7 @@
           grpc_service_config_create(service_config_json);
       if (service_config != NULL) {
         method_params_table = grpc_service_config_create_method_config_table(
-            service_config, method_parameters_create_from_json,
+            exec_ctx, service_config, method_parameters_create_from_json,
             &method_parameters_vtable);
         grpc_service_config_destroy(service_config);
       }
@@ -335,7 +341,7 @@
     // be pointing to data inside chand->resolver_result.
     // The copy will be saved in chand->lb_policy_name below.
     lb_policy_name = gpr_strdup(lb_policy_name);
-    grpc_channel_args_destroy(chand->resolver_result);
+    grpc_channel_args_destroy(exec_ctx, chand->resolver_result);
     chand->resolver_result = NULL;
   }
 
@@ -356,18 +362,16 @@
     chand->service_config_json = service_config_json;
   }
   if (chand->method_params_table != NULL) {
-    grpc_mdstr_hash_table_unref(chand->method_params_table);
+    grpc_mdstr_hash_table_unref(exec_ctx, chand->method_params_table);
   }
   chand->method_params_table = method_params_table;
   if (lb_policy != NULL) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
-                               NULL);
+    grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
   } else if (chand->resolver == NULL /* disconnected */) {
     grpc_closure_list_fail_all(
         &chand->waiting_for_config_closures,
         GRPC_ERROR_CREATE_REFERENCING("Channel disconnected", &error, 1));
-    grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
-                               NULL);
+    grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
   }
   if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
     GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
@@ -424,7 +428,7 @@
                                   grpc_transport_op *op) {
   channel_data *chand = elem->channel_data;
 
-  grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
 
   GPR_ASSERT(op->set_accept_stream == false);
   if (op->bind_pollset != NULL) {
@@ -443,9 +447,8 @@
 
   if (op->send_ping != NULL) {
     if (chand->lb_policy == NULL) {
-      grpc_exec_ctx_sched(exec_ctx, op->send_ping,
-                          GRPC_ERROR_CREATE("Ping with no load balancing"),
-                          NULL);
+      grpc_closure_sched(exec_ctx, op->send_ping,
+                         GRPC_ERROR_CREATE("Ping with no load balancing"));
     } else {
       grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
       op->bind_pollset = NULL;
@@ -464,8 +467,7 @@
       if (!chand->started_resolving) {
         grpc_closure_list_fail_all(&chand->waiting_for_config_closures,
                                    GRPC_ERROR_REF(op->disconnect_with_error));
-        grpc_exec_ctx_enqueue_list(exec_ctx,
-                                   &chand->waiting_for_config_closures, NULL);
+        grpc_closure_list_sched(exec_ctx, &chand->waiting_for_config_closures);
       }
       if (chand->lb_policy != NULL) {
         grpc_pollset_set_del_pollset_set(exec_ctx,
@@ -499,24 +501,40 @@
 }
 
 /* Constructor for channel_data */
-static void cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem,
-                                 grpc_channel_element_args *args) {
+static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_element *elem,
+                                        grpc_channel_element_args *args) {
   channel_data *chand = elem->channel_data;
-
   memset(chand, 0, sizeof(*chand));
-
   GPR_ASSERT(args->is_last);
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
-
+  // Initialize data members.
   gpr_mu_init(&chand->mu);
-  grpc_closure_init(&chand->on_resolver_result_changed,
-                    on_resolver_result_changed, chand);
   chand->owning_stack = args->channel_stack;
-
+  grpc_closure_init(&chand->on_resolver_result_changed,
+                    on_resolver_result_changed, chand,
+                    grpc_schedule_on_exec_ctx);
+  chand->interested_parties = grpc_pollset_set_create();
   grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
                                "client_channel");
-  chand->interested_parties = grpc_pollset_set_create();
+  // Record client channel factory.
+  const grpc_arg *arg = grpc_channel_args_find(args->channel_args,
+                                               GRPC_ARG_CLIENT_CHANNEL_FACTORY);
+  GPR_ASSERT(arg != NULL);
+  GPR_ASSERT(arg->type == GRPC_ARG_POINTER);
+  grpc_client_channel_factory_ref(arg->value.pointer.p);
+  chand->client_channel_factory = arg->value.pointer.p;
+  // Instantiate resolver.
+  arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_SERVER_URI);
+  GPR_ASSERT(arg != NULL);
+  GPR_ASSERT(arg->type == GRPC_ARG_STRING);
+  chand->resolver =
+      grpc_resolver_create(exec_ctx, arg->value.string, args->channel_args,
+                           chand->interested_parties);
+  if (chand->resolver == NULL) {
+    return GRPC_ERROR_CREATE("resolver creation failed");
+  }
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel_data */
@@ -540,7 +558,7 @@
   gpr_free(chand->lb_policy_name);
   gpr_free(chand->service_config_json);
   if (chand->method_params_table != NULL) {
-    grpc_mdstr_hash_table_unref(chand->method_params_table);
+    grpc_mdstr_hash_table_unref(exec_ctx, chand->method_params_table);
   }
   grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
   grpc_pollset_set_destroy(chand->interested_parties);
@@ -662,8 +680,9 @@
   calld->waiting_ops_count = 0;
   calld->waiting_ops_capacity = 0;
   GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
-  grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(retry_ops, a),
-                      GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(
+      exec_ctx, grpc_closure_create(retry_ops, a, grpc_schedule_on_exec_ctx),
+      GRPC_ERROR_NONE);
 }
 
 static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
@@ -683,9 +702,15 @@
                                      "Failed to create subchannel", &error, 1));
   } else if (GET_CALL(calld) == CANCELLED_CALL) {
     /* already cancelled before subchannel became ready */
-    fail_locked(exec_ctx, calld,
-                GRPC_ERROR_CREATE_REFERENCING(
-                    "Cancelled before creating subchannel", &error, 1));
+    grpc_error *cancellation_error = GRPC_ERROR_CREATE_REFERENCING(
+        "Cancelled before creating subchannel", &error, 1);
+    /* if due to deadline, attach the deadline exceeded status to the error */
+    if (gpr_time_cmp(calld->deadline, gpr_now(GPR_CLOCK_MONOTONIC)) < 0) {
+      cancellation_error =
+          grpc_error_set_int(cancellation_error, GRPC_ERROR_INT_GRPC_STATUS,
+                             GRPC_STATUS_DEADLINE_EXCEEDED);
+    }
+    fail_locked(exec_ctx, calld, cancellation_error);
   } else {
     /* Create call on subchannel. */
     grpc_subchannel_call *subchannel_call = NULL;
@@ -739,14 +764,14 @@
   if (cpa->connected_subchannel == NULL) {
     /* cancelled, do nothing */
   } else if (error != GRPC_ERROR_NONE) {
-    grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL);
+    grpc_closure_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error));
   } else {
     call_data *calld = cpa->elem->call_data;
     gpr_mu_lock(&calld->mu);
     if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
                         cpa->initial_metadata_flags, cpa->connected_subchannel,
                         cpa->on_ready, GRPC_ERROR_NONE)) {
-      grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL);
+      grpc_closure_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE);
     }
     gpr_mu_unlock(&calld->mu);
   }
@@ -778,9 +803,9 @@
       cpa = closure->cb_arg;
       if (cpa->connected_subchannel == connected_subchannel) {
         cpa->connected_subchannel = NULL;
-        grpc_exec_ctx_sched(
+        grpc_closure_sched(
             exec_ctx, cpa->on_ready,
-            GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1), NULL);
+            GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
       }
     }
     gpr_mu_unlock(&chand->mu);
@@ -809,7 +834,6 @@
         initial_metadata_flags &= ~GRPC_INITIAL_METADATA_WAIT_FOR_READY;
       }
     }
-    // TODO(dgq): make this deadline configurable somehow.
     const grpc_lb_policy_pick_args inputs = {
         initial_metadata, initial_metadata_flags, &calld->lb_token_mdelem,
         gpr_inf_future(GPR_CLOCK_MONOTONIC)};
@@ -832,12 +856,12 @@
     cpa->connected_subchannel = connected_subchannel;
     cpa->on_ready = on_ready;
     cpa->elem = elem;
-    grpc_closure_init(&cpa->closure, continue_picking, cpa);
+    grpc_closure_init(&cpa->closure, continue_picking, cpa,
+                      grpc_schedule_on_exec_ctx);
     grpc_closure_list_append(&chand->waiting_for_config_closures, &cpa->closure,
                              GRPC_ERROR_NONE);
   } else {
-    grpc_exec_ctx_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"));
   }
   gpr_mu_unlock(&chand->mu);
 
@@ -922,7 +946,8 @@
       calld->connected_subchannel == NULL &&
       op->send_initial_metadata != NULL) {
     calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
-    grpc_closure_init(&calld->next_step, subchannel_ready, elem);
+    grpc_closure_init(&calld->next_step, subchannel_ready, elem,
+                      grpc_schedule_on_exec_ctx);
     GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel");
     /* If a subchannel is not available immediately, the polling entity from
        call_data should be provided to channel_data's interested_parties, so
@@ -980,8 +1005,8 @@
     gpr_mu_unlock(&chand->mu);
     // If the method config table was present, use it.
     if (method_params_table != NULL) {
-      const method_parameters *method_params =
-          grpc_method_config_table_get(method_params_table, calld->path);
+      const method_parameters *method_params = grpc_method_config_table_get(
+          exec_ctx, method_params_table, calld->path);
       if (method_params != NULL) {
         const bool have_method_timeout =
             gpr_time_cmp(method_params->timeout, gpr_time_0(GPR_TIMESPAN)) != 0;
@@ -1004,7 +1029,7 @@
           gpr_mu_unlock(&calld->mu);
         }
       }
-      grpc_mdstr_hash_table_unref(method_params_table);
+      grpc_mdstr_hash_table_unref(exec_ctx, method_params_table);
     }
   }
   GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "read_service_config");
@@ -1045,8 +1070,8 @@
       grpc_mdstr_hash_table *method_params_table =
           grpc_mdstr_hash_table_ref(chand->method_params_table);
       gpr_mu_unlock(&chand->mu);
-      method_parameters *method_params =
-          grpc_method_config_table_get(method_params_table, args->path);
+      method_parameters *method_params = grpc_method_config_table_get(
+          exec_ctx, method_params_table, args->path);
       if (method_params != NULL) {
         if (gpr_time_cmp(method_params->timeout,
                          gpr_time_0(GPR_CLOCK_MONOTONIC)) != 0) {
@@ -1059,7 +1084,7 @@
               method_params->wait_for_ready;
         }
       }
-      grpc_mdstr_hash_table_unref(method_params_table);
+      grpc_mdstr_hash_table_unref(exec_ctx, method_params_table);
     } else {
       gpr_mu_unlock(&chand->mu);
     }
@@ -1068,7 +1093,8 @@
     // get the service config data once the resolver returns.
     // Take a reference to the call stack to be owned by the callback.
     GRPC_CALL_STACK_REF(calld->owning_call, "read_service_config");
-    grpc_closure_init(&calld->read_service_config, read_service_config, elem);
+    grpc_closure_init(&calld->read_service_config, read_service_config, elem,
+                      grpc_schedule_on_exec_ctx);
     grpc_closure_list_append(&chand->waiting_for_config_closures,
                              &calld->read_service_config, GRPC_ERROR_NONE);
     gpr_mu_unlock(&chand->mu);
@@ -1087,7 +1113,7 @@
                                  void *and_free_memory) {
   call_data *calld = elem->call_data;
   grpc_deadline_state_destroy(exec_ctx, elem);
-  GRPC_MDSTR_UNREF(calld->path);
+  GRPC_MDSTR_UNREF(exec_ctx, calld->path);
   GRPC_ERROR_UNREF(calld->cancel_error);
   grpc_subchannel_call *call = GET_CALL(calld);
   if (call != NULL && call != CANCELLED_CALL) {
@@ -1130,30 +1156,6 @@
     "client-channel",
 };
 
-void grpc_client_channel_finish_initialization(
-    grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
-    grpc_resolver *resolver,
-    grpc_client_channel_factory *client_channel_factory) {
-  /* post construction initialization: set the transport setup pointer */
-  GPR_ASSERT(client_channel_factory != NULL);
-  grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
-  channel_data *chand = elem->channel_data;
-  gpr_mu_lock(&chand->mu);
-  GPR_ASSERT(!chand->resolver);
-  chand->resolver = resolver;
-  GRPC_RESOLVER_REF(resolver, "channel");
-  if (!grpc_closure_list_empty(chand->waiting_for_config_closures) ||
-      chand->exit_idle_when_lb_policy_arrives) {
-    chand->started_resolving = true;
-    GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, resolver, &chand->resolver_result,
-                       &chand->on_resolver_result_changed);
-  }
-  chand->client_channel_factory = client_channel_factory;
-  grpc_client_channel_factory_ref(client_channel_factory);
-  gpr_mu_unlock(&chand->mu);
-}
-
 grpc_connectivity_state grpc_client_channel_check_connectivity_state(
     grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
   channel_data *chand = elem->channel_data;
@@ -1205,7 +1207,8 @@
   w->pollset = pollset;
   w->on_complete = on_complete;
   grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
-  grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
+  grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
+                    grpc_schedule_on_exec_ctx);
   GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
                          "external_connectivity_watcher");
   gpr_mu_lock(&chand->mu);
diff --git a/src/core/ext/client_channel/client_channel.h b/src/core/ext/client_channel/client_channel.h
index ab5a84f..f02587d 100644
--- a/src/core/ext/client_channel/client_channel.h
+++ b/src/core/ext/client_channel/client_channel.h
@@ -38,6 +38,9 @@
 #include "src/core/ext/client_channel/resolver.h"
 #include "src/core/lib/channel/channel_stack.h"
 
+// Channel arg key for server URI string.
+#define GRPC_ARG_SERVER_URI "grpc.server_uri"
+
 /* A client channel is a channel that begins disconnected, and can connect
    to some endpoint on demand. If that endpoint disconnects, it will be
    connected to again later.
@@ -47,13 +50,6 @@
 
 extern const grpc_channel_filter grpc_client_channel_filter;
 
-/* Post-construction initializer to give the client channel its resolver
-   and factory. */
-void grpc_client_channel_finish_initialization(
-    grpc_exec_ctx *exec_ctx, grpc_channel_stack *channel_stack,
-    grpc_resolver *resolver,
-    grpc_client_channel_factory *client_channel_factory);
-
 grpc_connectivity_state grpc_client_channel_check_connectivity_state(
     grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect);
 
diff --git a/src/core/ext/client_channel/client_channel_factory.c b/src/core/ext/client_channel/client_channel_factory.c
index 4900832..d2707a1 100644
--- a/src/core/ext/client_channel/client_channel_factory.c
+++ b/src/core/ext/client_channel/client_channel_factory.c
@@ -55,3 +55,33 @@
   return factory->vtable->create_client_channel(exec_ctx, factory, target, type,
                                                 args);
 }
+
+static void* factory_arg_copy(void* factory) {
+  grpc_client_channel_factory_ref(factory);
+  return factory;
+}
+
+static void factory_arg_destroy(grpc_exec_ctx* exec_ctx, void* factory) {
+  // TODO(roth): Remove local exec_ctx when
+  // https://github.com/grpc/grpc/pull/8705 is merged.
+  grpc_client_channel_factory_unref(exec_ctx, factory);
+}
+
+static int factory_arg_cmp(void* factory1, void* factory2) {
+  if (factory1 < factory2) return -1;
+  if (factory1 > factory2) return 1;
+  return 0;
+}
+
+static const grpc_arg_pointer_vtable factory_arg_vtable = {
+    factory_arg_copy, factory_arg_destroy, factory_arg_cmp};
+
+grpc_arg grpc_client_channel_factory_create_channel_arg(
+    grpc_client_channel_factory* factory) {
+  grpc_arg arg;
+  arg.type = GRPC_ARG_POINTER;
+  arg.key = GRPC_ARG_CLIENT_CHANNEL_FACTORY;
+  arg.value.pointer.p = factory;
+  arg.value.pointer.vtable = &factory_arg_vtable;
+  return arg;
+}
diff --git a/src/core/ext/client_channel/client_channel_factory.h b/src/core/ext/client_channel/client_channel_factory.h
index 2b8fc57..bf2764b 100644
--- a/src/core/ext/client_channel/client_channel_factory.h
+++ b/src/core/ext/client_channel/client_channel_factory.h
@@ -39,6 +39,9 @@
 #include "src/core/ext/client_channel/subchannel.h"
 #include "src/core/lib/channel/channel_stack.h"
 
+// Channel arg key for client channel factory.
+#define GRPC_ARG_CLIENT_CHANNEL_FACTORY "grpc.client_channel_factory"
+
 typedef struct grpc_client_channel_factory grpc_client_channel_factory;
 typedef struct grpc_client_channel_factory_vtable
     grpc_client_channel_factory_vtable;
@@ -83,4 +86,7 @@
     const char *target, grpc_client_channel_type type,
     const grpc_channel_args *args);
 
+grpc_arg grpc_client_channel_factory_create_channel_arg(
+    grpc_client_channel_factory *factory);
+
 #endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H */
diff --git a/src/core/ext/client_channel/client_channel_plugin.c b/src/core/ext/client_channel/client_channel_plugin.c
index a3e5079..d50bba6 100644
--- a/src/core/ext/client_channel/client_channel_plugin.c
+++ b/src/core/ext/client_channel/client_channel_plugin.c
@@ -38,17 +38,20 @@
 #include <grpc/support/alloc.h>
 
 #include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/client_channel/http_connect_handshaker.h"
 #include "src/core/ext/client_channel/lb_policy_registry.h"
 #include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/client_channel/subchannel_index.h"
 #include "src/core/lib/surface/channel_init.h"
 
-static bool append_filter(grpc_channel_stack_builder *builder, void *arg) {
+static bool append_filter(grpc_exec_ctx *exec_ctx,
+                          grpc_channel_stack_builder *builder, void *arg) {
   return grpc_channel_stack_builder_append_filter(
       builder, (const grpc_channel_filter *)arg, NULL, NULL);
 }
 
-static bool set_default_host_if_unset(grpc_channel_stack_builder *builder,
+static bool set_default_host_if_unset(grpc_exec_ctx *exec_ctx,
+                                      grpc_channel_stack_builder *builder,
                                       void *unused) {
   const grpc_channel_args *args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
@@ -66,9 +69,10 @@
     arg.key = GRPC_ARG_DEFAULT_AUTHORITY;
     arg.value.string = default_authority;
     grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
-    grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
+    grpc_channel_stack_builder_set_channel_arguments(exec_ctx, builder,
+                                                     new_args);
     gpr_free(default_authority);
-    grpc_channel_args_destroy(new_args);
+    grpc_channel_args_destroy(exec_ctx, new_args);
   }
   return true;
 }
@@ -81,6 +85,7 @@
                                    set_default_host_if_unset, NULL);
   grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX, append_filter,
                                    (void *)&grpc_client_channel_filter);
+  grpc_http_connect_register_handshaker_factory();
 }
 
 void grpc_client_channel_shutdown(void) {
diff --git a/src/core/ext/client_channel/http_connect_handshaker.c b/src/core/ext/client_channel/http_connect_handshaker.c
index 572af52..fba3256 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.c
+++ b/src/core/ext/client_channel/http_connect_handshaker.c
@@ -40,10 +40,14 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/ext/client_channel/client_channel.h"
+#include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/http/format_request.h"
 #include "src/core/lib/http/parser.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/env.h"
 
 typedef struct http_connect_handshaker {
@@ -51,7 +55,8 @@
   grpc_handshaker base;
 
   char* proxy_server;
-  char* server_name;
+  grpc_http_header* headers;
+  size_t num_headers;
 
   gpr_refcount refcount;
   gpr_mu mu;
@@ -82,12 +87,17 @@
       grpc_endpoint_destroy(exec_ctx, handshaker->endpoint_to_destroy);
     }
     if (handshaker->read_buffer_to_destroy != NULL) {
-      grpc_slice_buffer_destroy(handshaker->read_buffer_to_destroy);
+      grpc_slice_buffer_destroy_internal(exec_ctx,
+                                         handshaker->read_buffer_to_destroy);
       gpr_free(handshaker->read_buffer_to_destroy);
     }
     gpr_free(handshaker->proxy_server);
-    gpr_free(handshaker->server_name);
-    grpc_slice_buffer_destroy(&handshaker->write_buffer);
+    for (size_t i = 0; i < handshaker->num_headers; ++i) {
+      gpr_free(handshaker->headers[i].key);
+      gpr_free(handshaker->headers[i].value);
+    }
+    gpr_free(handshaker->headers);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &handshaker->write_buffer);
     grpc_http_parser_destroy(&handshaker->http_parser);
     grpc_http_response_destroy(&handshaker->http_response);
     gpr_free(handshaker);
@@ -97,12 +107,12 @@
 // Set args fields to NULL, saving the endpoint and read buffer for
 // later destruction.
 static void cleanup_args_for_failure_locked(
-    http_connect_handshaker* handshaker) {
+    grpc_exec_ctx* exec_ctx, http_connect_handshaker* handshaker) {
   handshaker->endpoint_to_destroy = handshaker->args->endpoint;
   handshaker->args->endpoint = NULL;
   handshaker->read_buffer_to_destroy = handshaker->args->read_buffer;
   handshaker->args->read_buffer = NULL;
-  grpc_channel_args_destroy(handshaker->args->args);
+  grpc_channel_args_destroy(exec_ctx, handshaker->args->args);
   handshaker->args->args = NULL;
 }
 
@@ -125,13 +135,13 @@
     grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint);
     // Not shutting down, so the handshake failed.  Clean up before
     // invoking the callback.
-    cleanup_args_for_failure_locked(handshaker);
+    cleanup_args_for_failure_locked(exec_ctx, handshaker);
     // Set shutdown to true so that subsequent calls to
     // http_connect_handshaker_shutdown() do nothing.
     handshaker->shutdown = true;
   }
   // Invoke callback.
-  grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL);
+  grpc_closure_sched(exec_ctx, handshaker->on_handshake_done, error);
 }
 
 // Callback invoked when finished writing HTTP CONNECT request.
@@ -193,7 +203,7 @@
                                &handshaker->args->read_buffer->slices[i + 1],
                                handshaker->args->read_buffer->count - i - 1);
         grpc_slice_buffer_swap(handshaker->args->read_buffer, &tmp_buffer);
-        grpc_slice_buffer_destroy(&tmp_buffer);
+        grpc_slice_buffer_destroy_internal(exec_ctx, &tmp_buffer);
         break;
       }
     }
@@ -210,7 +220,8 @@
   // complete (e.g., handling chunked transfer encoding or looking
   // at the Content-Length: header).
   if (handshaker->http_parser.state != GRPC_HTTP_BODY) {
-    grpc_slice_buffer_reset_and_unref(handshaker->args->read_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                               handshaker->args->read_buffer);
     grpc_endpoint_read(exec_ctx, handshaker->args->endpoint,
                        handshaker->args->read_buffer,
                        &handshaker->response_read_closure);
@@ -229,7 +240,7 @@
     goto done;
   }
   // Success.  Invoke handshake-done callback.
-  grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL);
+  grpc_closure_sched(exec_ctx, handshaker->on_handshake_done, error);
 done:
   // Set shutdown to true so that subsequent calls to
   // http_connect_handshaker_shutdown() do nothing.
@@ -255,7 +266,7 @@
   if (!handshaker->shutdown) {
     handshaker->shutdown = true;
     grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint);
-    cleanup_args_for_failure_locked(handshaker);
+    cleanup_args_for_failure_locked(exec_ctx, handshaker);
   }
   gpr_mu_unlock(&handshaker->mu);
 }
@@ -265,18 +276,29 @@
     grpc_tcp_server_acceptor* acceptor, grpc_closure* on_handshake_done,
     grpc_handshaker_args* args) {
   http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in;
-  gpr_mu_lock(&handshaker->mu);
+  // Get server name from channel args.
+  const grpc_arg* arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI);
+  GPR_ASSERT(arg != NULL);
+  GPR_ASSERT(arg->type == GRPC_ARG_STRING);
+  char* canonical_uri =
+      grpc_resolver_factory_add_default_prefix_if_needed(arg->value.string);
+  grpc_uri* uri = grpc_uri_parse(canonical_uri, 1);
+  char* server_name = uri->path;
+  if (server_name[0] == '/') ++server_name;
   // Save state in the handshaker object.
+  gpr_mu_lock(&handshaker->mu);
   handshaker->args = args;
   handshaker->on_handshake_done = on_handshake_done;
   // Send HTTP CONNECT request.
-  gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s",
-          handshaker->server_name, handshaker->proxy_server);
+  gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", server_name,
+          handshaker->proxy_server);
   grpc_httpcli_request request;
   memset(&request, 0, sizeof(request));
-  request.host = handshaker->proxy_server;
+  request.host = server_name;
   request.http.method = "CONNECT";
-  request.http.path = handshaker->server_name;
+  request.http.path = server_name;
+  request.http.hdrs = handshaker->headers;
+  request.http.hdr_count = handshaker->num_headers;
   request.handshaker = &grpc_httpcli_plaintext;
   grpc_slice request_slice = grpc_httpcli_format_connect_request(&request);
   grpc_slice_buffer_add(&handshaker->write_buffer, request_slice);
@@ -285,6 +307,9 @@
   grpc_endpoint_write(exec_ctx, args->endpoint, &handshaker->write_buffer,
                       &handshaker->request_done_closure);
   gpr_mu_unlock(&handshaker->mu);
+  // Clean up.
+  gpr_free(canonical_uri);
+  grpc_uri_destroy(uri);
 }
 
 static const grpc_handshaker_vtable http_connect_handshaker_vtable = {
@@ -292,21 +317,28 @@
     http_connect_handshaker_do_handshake};
 
 grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
-                                                     const char* server_name) {
+                                                     grpc_http_header* headers,
+                                                     size_t num_headers) {
   GPR_ASSERT(proxy_server != NULL);
-  GPR_ASSERT(server_name != NULL);
   http_connect_handshaker* handshaker = gpr_malloc(sizeof(*handshaker));
   memset(handshaker, 0, sizeof(*handshaker));
   grpc_handshaker_init(&http_connect_handshaker_vtable, &handshaker->base);
   gpr_mu_init(&handshaker->mu);
   gpr_ref_init(&handshaker->refcount, 1);
   handshaker->proxy_server = gpr_strdup(proxy_server);
-  handshaker->server_name = gpr_strdup(server_name);
+  if (num_headers > 0) {
+    handshaker->headers = gpr_malloc(sizeof(grpc_http_header) * num_headers);
+    for (size_t i = 0; i < num_headers; ++i) {
+      handshaker->headers[i].key = gpr_strdup(headers[i].key);
+      handshaker->headers[i].value = gpr_strdup(headers[i].value);
+    }
+    handshaker->num_headers = num_headers;
+  }
   grpc_slice_buffer_init(&handshaker->write_buffer);
   grpc_closure_init(&handshaker->request_done_closure, on_write_done,
-                    handshaker);
+                    handshaker, grpc_schedule_on_exec_ctx);
   grpc_closure_init(&handshaker->response_read_closure, on_read_done,
-                    handshaker);
+                    handshaker, grpc_schedule_on_exec_ctx);
   grpc_http_parser_init(&handshaker->http_parser, GRPC_HTTP_RESPONSE,
                         &handshaker->http_response);
   return &handshaker->base;
@@ -335,3 +367,33 @@
   grpc_uri_destroy(uri);
   return proxy_name;
 }
+
+//
+// handshaker factory
+//
+
+static void handshaker_factory_add_handshakers(
+    grpc_exec_ctx* exec_ctx, grpc_handshaker_factory* factory,
+    const grpc_channel_args* args, grpc_handshake_manager* handshake_mgr) {
+  char* proxy_name = grpc_get_http_proxy_server();
+  if (proxy_name != NULL) {
+    grpc_handshake_manager_add(
+        handshake_mgr,
+        grpc_http_connect_handshaker_create(proxy_name, NULL, 0));
+    gpr_free(proxy_name);
+  }
+}
+
+static void handshaker_factory_destroy(grpc_exec_ctx* exec_ctx,
+                                       grpc_handshaker_factory* factory) {}
+
+static const grpc_handshaker_factory_vtable handshaker_factory_vtable = {
+    handshaker_factory_add_handshakers, handshaker_factory_destroy};
+
+static grpc_handshaker_factory handshaker_factory = {
+    &handshaker_factory_vtable};
+
+void grpc_http_connect_register_handshaker_factory() {
+  grpc_handshaker_factory_register(true /* at_start */, HANDSHAKER_CLIENT,
+                                   &handshaker_factory);
+}
diff --git a/src/core/ext/client_channel/http_connect_handshaker.h b/src/core/ext/client_channel/http_connect_handshaker.h
index c689df2..c2e68de 100644
--- a/src/core/ext/client_channel/http_connect_handshaker.h
+++ b/src/core/ext/client_channel/http_connect_handshaker.h
@@ -35,13 +35,18 @@
 #define GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H
 
 #include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/http/parser.h"
 
-/// Does NOT take ownership of \a proxy_server or \a server_name.
+/// Creates a new HTTP CONNECT handshaker.
 grpc_handshaker* grpc_http_connect_handshaker_create(const char* proxy_server,
-                                                     const char* server_name);
+                                                     grpc_http_header* headers,
+                                                     size_t num_headers);
 
 /// Returns the name of the proxy to use, or NULL if no proxy is configured.
 /// Caller takes ownership of result.
 char* grpc_get_http_proxy_server();
 
+/// Registers handshaker factory.
+void grpc_http_connect_register_handshaker_factory();
+
 #endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H */
diff --git a/src/core/ext/client_channel/lb_policy_factory.c b/src/core/ext/client_channel/lb_policy_factory.c
index 8a474c8..7af9bb0 100644
--- a/src/core/ext/client_channel/lb_policy_factory.c
+++ b/src/core/ext/client_channel/lb_policy_factory.c
@@ -112,11 +112,13 @@
   return 0;
 }
 
-void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) {
+void grpc_lb_addresses_destroy(grpc_exec_ctx* exec_ctx,
+                               grpc_lb_addresses* addresses) {
   for (size_t i = 0; i < addresses->num_addresses; ++i) {
     gpr_free(addresses->addresses[i].balancer_name);
     if (addresses->addresses[i].user_data != NULL) {
-      addresses->user_data_vtable->destroy(addresses->addresses[i].user_data);
+      addresses->user_data_vtable->destroy(exec_ctx,
+                                           addresses->addresses[i].user_data);
     }
   }
   gpr_free(addresses->addresses);
@@ -126,8 +128,8 @@
 static void* lb_addresses_copy(void* addresses) {
   return grpc_lb_addresses_copy(addresses);
 }
-static void lb_addresses_destroy(void* addresses) {
-  grpc_lb_addresses_destroy(addresses);
+static void lb_addresses_destroy(grpc_exec_ctx* exec_ctx, void* addresses) {
+  grpc_lb_addresses_destroy(exec_ctx, addresses);
 }
 static int lb_addresses_cmp(void* addresses1, void* addresses2) {
   return grpc_lb_addresses_cmp(addresses1, addresses2);
diff --git a/src/core/ext/client_channel/lb_policy_factory.h b/src/core/ext/client_channel/lb_policy_factory.h
index e2b8080..9b8b03f 100644
--- a/src/core/ext/client_channel/lb_policy_factory.h
+++ b/src/core/ext/client_channel/lb_policy_factory.h
@@ -40,6 +40,9 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
+// Channel arg key for grpc_lb_addresses.
+#define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses"
+
 typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
 typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
 
@@ -61,7 +64,7 @@
 
 typedef struct grpc_lb_user_data_vtable {
   void *(*copy)(void *);
-  void (*destroy)(void *);
+  void (*destroy)(grpc_exec_ctx *exec_ctx, void *);
   int (*cmp)(void *, void *);
 } grpc_lb_user_data_vtable;
 
@@ -93,7 +96,8 @@
                           const grpc_lb_addresses *addresses2);
 
 /** Destroys \a addresses. */
-void grpc_lb_addresses_destroy(grpc_lb_addresses *addresses);
+void grpc_lb_addresses_destroy(grpc_exec_ctx *exec_ctx,
+                               grpc_lb_addresses *addresses);
 
 /** Returns a channel arg containing \a addresses. */
 grpc_arg grpc_lb_addresses_create_channel_arg(
diff --git a/src/core/ext/client_channel/resolver_factory.c b/src/core/ext/client_channel/resolver_factory.c
index 7c3d644..00bbb92 100644
--- a/src/core/ext/client_channel/resolver_factory.c
+++ b/src/core/ext/client_channel/resolver_factory.c
@@ -43,9 +43,10 @@
 
 /** Create a resolver instance for a name */
 grpc_resolver* grpc_resolver_factory_create_resolver(
-    grpc_resolver_factory* factory, grpc_resolver_args* args) {
+    grpc_exec_ctx* exec_ctx, grpc_resolver_factory* factory,
+    grpc_resolver_args* args) {
   if (factory == NULL) return NULL;
-  return factory->vtable->create_resolver(factory, args);
+  return factory->vtable->create_resolver(exec_ctx, factory, args);
 }
 
 char* grpc_resolver_factory_get_default_authority(
diff --git a/src/core/ext/client_channel/resolver_factory.h b/src/core/ext/client_channel/resolver_factory.h
index 4da42e8..3792ddc 100644
--- a/src/core/ext/client_channel/resolver_factory.h
+++ b/src/core/ext/client_channel/resolver_factory.h
@@ -37,6 +37,7 @@
 #include "src/core/ext/client_channel/client_channel_factory.h"
 #include "src/core/ext/client_channel/resolver.h"
 #include "src/core/ext/client_channel/uri_parser.h"
+#include "src/core/lib/iomgr/pollset_set.h"
 
 typedef struct grpc_resolver_factory grpc_resolver_factory;
 typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
@@ -48,6 +49,7 @@
 typedef struct grpc_resolver_args {
   grpc_uri *uri;
   const grpc_channel_args *args;
+  grpc_pollset_set *pollset_set;
 } grpc_resolver_args;
 
 struct grpc_resolver_factory_vtable {
@@ -55,7 +57,8 @@
   void (*unref)(grpc_resolver_factory *factory);
 
   /** Implementation of grpc_resolver_factory_create_resolver */
-  grpc_resolver *(*create_resolver)(grpc_resolver_factory *factory,
+  grpc_resolver *(*create_resolver)(grpc_exec_ctx *exec_ctx,
+                                    grpc_resolver_factory *factory,
                                     grpc_resolver_args *args);
 
   /** Implementation of grpc_resolver_factory_get_default_authority */
@@ -70,7 +73,8 @@
 
 /** Create a resolver instance for a name */
 grpc_resolver *grpc_resolver_factory_create_resolver(
-    grpc_resolver_factory *factory, grpc_resolver_args *args);
+    grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory,
+    grpc_resolver_args *args);
 
 /** Return a (freshly allocated with gpr_malloc) string representing
     the default authority to use for this scheme. */
diff --git a/src/core/ext/client_channel/resolver_registry.c b/src/core/ext/client_channel/resolver_registry.c
index d0f0fc3..5110a7c 100644
--- a/src/core/ext/client_channel/resolver_registry.c
+++ b/src/core/ext/client_channel/resolver_registry.c
@@ -109,8 +109,8 @@
 }
 
 static grpc_resolver_factory *resolve_factory(const char *target,
-                                              grpc_uri **uri) {
-  char *tmp;
+                                              grpc_uri **uri,
+                                              char **canonical_target) {
   grpc_resolver_factory *factory = NULL;
 
   GPR_ASSERT(uri != NULL);
@@ -118,37 +118,54 @@
   factory = lookup_factory_by_uri(*uri);
   if (factory == NULL) {
     grpc_uri_destroy(*uri);
-    gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target);
-    *uri = grpc_uri_parse(tmp, 1);
+    gpr_asprintf(canonical_target, "%s%s", g_default_resolver_prefix, target);
+    *uri = grpc_uri_parse(*canonical_target, 1);
     factory = lookup_factory_by_uri(*uri);
     if (factory == NULL) {
       grpc_uri_destroy(grpc_uri_parse(target, 0));
-      grpc_uri_destroy(grpc_uri_parse(tmp, 0));
-      gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, tmp);
+      grpc_uri_destroy(grpc_uri_parse(*canonical_target, 0));
+      gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target,
+              *canonical_target);
     }
-    gpr_free(tmp);
   }
   return factory;
 }
 
-grpc_resolver *grpc_resolver_create(const char *target,
-                                    const grpc_channel_args *args) {
+grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target,
+                                    const grpc_channel_args *args,
+                                    grpc_pollset_set *pollset_set) {
   grpc_uri *uri = NULL;
-  grpc_resolver_factory *factory = resolve_factory(target, &uri);
+  char *canonical_target = NULL;
+  grpc_resolver_factory *factory =
+      resolve_factory(target, &uri, &canonical_target);
   grpc_resolver *resolver;
   grpc_resolver_args resolver_args;
   memset(&resolver_args, 0, sizeof(resolver_args));
   resolver_args.uri = uri;
   resolver_args.args = args;
-  resolver = grpc_resolver_factory_create_resolver(factory, &resolver_args);
+  resolver_args.pollset_set = pollset_set;
+  resolver =
+      grpc_resolver_factory_create_resolver(exec_ctx, factory, &resolver_args);
   grpc_uri_destroy(uri);
+  gpr_free(canonical_target);
   return resolver;
 }
 
 char *grpc_get_default_authority(const char *target) {
   grpc_uri *uri = NULL;
-  grpc_resolver_factory *factory = resolve_factory(target, &uri);
+  char *canonical_target = NULL;
+  grpc_resolver_factory *factory =
+      resolve_factory(target, &uri, &canonical_target);
   char *authority = grpc_resolver_factory_get_default_authority(factory, uri);
   grpc_uri_destroy(uri);
+  gpr_free(canonical_target);
   return authority;
 }
+
+char *grpc_resolver_factory_add_default_prefix_if_needed(const char *target) {
+  grpc_uri *uri = NULL;
+  char *canonical_target = NULL;
+  resolve_factory(target, &uri, &canonical_target);
+  grpc_uri_destroy(uri);
+  return canonical_target == NULL ? gpr_strdup(target) : canonical_target;
+}
diff --git a/src/core/ext/client_channel/resolver_registry.h b/src/core/ext/client_channel/resolver_registry.h
index 2a95a66..4fb1613 100644
--- a/src/core/ext/client_channel/resolver_registry.h
+++ b/src/core/ext/client_channel/resolver_registry.h
@@ -35,6 +35,7 @@
 #define GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H
 
 #include "src/core/ext/client_channel/resolver_factory.h"
+#include "src/core/lib/iomgr/pollset_set.h"
 
 void grpc_resolver_registry_init();
 void grpc_resolver_registry_shutdown(void);
@@ -60,8 +61,9 @@
     If a resolver factory was not found, return NULL.
     \a args is a set of channel arguments to be included in the result
     (typically the set of arguments passed in from the client API). */
-grpc_resolver *grpc_resolver_create(const char *target,
-                                    const grpc_channel_args *args);
+grpc_resolver *grpc_resolver_create(grpc_exec_ctx *exec_ctx, const char *target,
+                                    const grpc_channel_args *args,
+                                    grpc_pollset_set *pollset_set);
 
 /** Find a resolver factory given a name and return an (owned-by-the-caller)
  *  reference to it */
@@ -71,4 +73,8 @@
     representing the default authority to pass from a client. */
 char *grpc_get_default_authority(const char *target);
 
+/** Returns a newly allocated string containing \a target, adding the
+    default prefix if needed. */
+char *grpc_resolver_factory_add_default_prefix_if_needed(const char *target);
+
 #endif /* GRPC_CORE_EXT_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */
diff --git a/src/core/ext/client_channel/subchannel.c b/src/core/ext/client_channel/subchannel.c
index 0863207..1bac82b 100644
--- a/src/core/ext/client_channel/subchannel.c
+++ b/src/core/ext/client_channel/subchannel.c
@@ -46,6 +46,7 @@
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/backoff.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/channel_init.h"
@@ -108,6 +109,9 @@
   /** callback for connection finishing */
   grpc_closure connected;
 
+  /** callback for our alarm */
+  grpc_closure on_alarm;
+
   /** pollset_set tracking who's interested in a connection
       being setup */
   grpc_pollset_set *pollset_set;
@@ -206,9 +210,9 @@
                                grpc_error *error) {
   grpc_subchannel *c = arg;
   gpr_free((void *)c->filters);
-  grpc_channel_args_destroy(c->args);
+  grpc_channel_args_destroy(exec_ctx, c->args);
   gpr_free(c->addr);
-  grpc_slice_unref(c->initial_connect_string);
+  grpc_slice_unref_internal(exec_ctx, c->initial_connect_string);
   grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
   grpc_connector_unref(exec_ctx, c->connector);
   grpc_pollset_set_destroy(c->pollset_set);
@@ -293,8 +297,9 @@
   gpr_atm old_refs;
   old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
   if (old_refs == 1) {
-    grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(subchannel_destroy, c),
-                        GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, grpc_closure_create(subchannel_destroy, c,
+                                                     grpc_schedule_on_exec_ctx),
+                       GRPC_ERROR_NONE);
   }
 }
 
@@ -330,7 +335,8 @@
   c->args = grpc_channel_args_copy(args->args);
   c->root_external_state_watcher.next = c->root_external_state_watcher.prev =
       &c->root_external_state_watcher;
-  grpc_closure_init(&c->connected, subchannel_connected, c);
+  grpc_closure_init(&c->connected, subchannel_connected, c,
+                    grpc_schedule_on_exec_ctx);
   grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE,
                                "subchannel");
   int initial_backoff_ms =
@@ -480,7 +486,8 @@
       gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
               time_til_next.tv_sec, time_til_next.tv_nsec);
     }
-    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
+    grpc_closure_init(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx);
+    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm, now);
   }
 }
 
@@ -505,7 +512,8 @@
     w->subchannel = c;
     w->pollset_set = interested_parties;
     w->notify = notify;
-    grpc_closure_init(&w->closure, on_external_state_watcher_done, w);
+    grpc_closure_init(&w->closure, on_external_state_watcher_done, w,
+                      grpc_schedule_on_exec_ctx);
     if (interested_parties != NULL) {
       grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set,
                                        interested_parties);
@@ -600,18 +608,24 @@
   /* construct channel stack */
   grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create();
   grpc_channel_stack_builder_set_channel_arguments(
-      builder, c->connecting_result.channel_args);
+      exec_ctx, builder, c->connecting_result.channel_args);
   grpc_channel_stack_builder_set_transport(builder,
                                            c->connecting_result.transport);
 
-  if (grpc_channel_init_create_stack(exec_ctx, builder,
-                                     GRPC_CLIENT_SUBCHANNEL)) {
-    con = grpc_channel_stack_builder_finish(exec_ctx, builder, 0, 1,
-                                            connection_destroy, NULL);
-  } else {
-    grpc_channel_stack_builder_destroy(builder);
+  if (!grpc_channel_init_create_stack(exec_ctx, builder,
+                                      GRPC_CLIENT_SUBCHANNEL)) {
+    grpc_channel_stack_builder_destroy(exec_ctx, builder);
     abort(); /* TODO(ctiller): what to do here (previously we just crashed) */
   }
+  grpc_error *error = grpc_channel_stack_builder_finish(
+      exec_ctx, builder, 0, 1, connection_destroy, NULL, (void **)&con);
+  if (error != GRPC_ERROR_NONE) {
+    const char *msg = grpc_error_string(error);
+    gpr_log(GPR_ERROR, "error initializing subchannel stack: %s", msg);
+    grpc_error_free_string(msg);
+    GRPC_ERROR_UNREF(error);
+    abort(); /* TODO(ctiller): what to do here? */
+  }
   stk = CHANNEL_STACK_FROM_CONNECTION(con);
   memset(&c->connecting_result, 0, sizeof(c->connecting_result));
 
@@ -620,7 +634,7 @@
   sw_subchannel->subchannel = c;
   sw_subchannel->connectivity_state = GRPC_CHANNEL_READY;
   grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed,
-                    sw_subchannel);
+                    sw_subchannel, grpc_schedule_on_exec_ctx);
 
   if (c->disconnected) {
     gpr_free(sw_subchannel);
@@ -680,7 +694,7 @@
   }
   gpr_mu_unlock(&c->mu);
   GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connected");
-  grpc_channel_args_destroy(delete_channel_args);
+  grpc_channel_args_destroy(exec_ctx, delete_channel_args);
 }
 
 /*
diff --git a/src/core/ext/client_channel/subchannel.h b/src/core/ext/client_channel/subchannel.h
index 10bae62..24aa9f7 100644
--- a/src/core/ext/client_channel/subchannel.h
+++ b/src/core/ext/client_channel/subchannel.h
@@ -164,8 +164,6 @@
   size_t filter_count;
   /** Channel arguments to be supplied to the newly created channel */
   const grpc_channel_args *args;
-  /** Server name */
-  const char *server_name;
   /** Address to connect to */
   grpc_resolved_address *addr;
 };
diff --git a/src/core/ext/client_channel/subchannel_index.c b/src/core/ext/client_channel/subchannel_index.c
index 227013a..1ebe03e 100644
--- a/src/core/ext/client_channel/subchannel_index.c
+++ b/src/core/ext/client_channel/subchannel_index.c
@@ -86,7 +86,6 @@
   } else {
     k->args.filters = NULL;
   }
-  k->args.server_name = gpr_strdup(args->server_name);
   k->args.addr = gpr_malloc(sizeof(grpc_resolved_address));
   k->args.addr->len = args->addr->len;
   if (k->args.addr->len > 0) {
@@ -113,8 +112,6 @@
   if (c != 0) return c;
   c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
   if (c != 0) return c;
-  c = strcmp(a->args.server_name, b->args.server_name);
-  if (c != 0) return c;
   if (a->args.addr->len) {
     c = memcmp(a->args.addr->addr, b->args.addr->addr, a->args.addr->len);
     if (c != 0) return c;
@@ -131,8 +128,7 @@
                                  grpc_subchannel_key *k) {
   grpc_connector_unref(exec_ctx, k->connector);
   gpr_free((grpc_channel_args *)k->args.filters);
-  grpc_channel_args_destroy((grpc_channel_args *)k->args.args);
-  gpr_free((void *)k->args.server_name);
+  grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)k->args.args);
   gpr_free(k->args.addr);
   gpr_free(k);
 }
diff --git a/src/core/ext/client_channel/uri_parser.c b/src/core/ext/client_channel/uri_parser.c
index 0fbc542..f8c946b 100644
--- a/src/core/ext/client_channel/uri_parser.c
+++ b/src/core/ext/client_channel/uri_parser.c
@@ -42,7 +42,6 @@
 #include <grpc/support/port_platform.h>
 #include <grpc/support/string_util.h>
 
-#include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
 /** a size_t default value... maps to all 1's */
@@ -138,7 +137,6 @@
   return 1;
 }
 
-static void do_nothing(void *ignored) {}
 static void parse_query_parts(grpc_uri *uri) {
   static const char *QUERY_PARTS_SEPARATOR = "&";
   static const char *QUERY_PARTS_VALUE_SEPARATOR = "=";
@@ -149,38 +147,32 @@
     uri->num_query_parts = 0;
     return;
   }
-  grpc_slice query_slice =
-      grpc_slice_new(uri->query, strlen(uri->query), do_nothing);
-  grpc_slice_buffer query_parts; /* the &-separated elements of the query */
-  grpc_slice_buffer query_param_parts; /* the =-separated subelements */
 
-  grpc_slice_buffer_init(&query_parts);
-  grpc_slice_buffer_init(&query_param_parts);
-
-  grpc_slice_split(query_slice, QUERY_PARTS_SEPARATOR, &query_parts);
-  uri->query_parts = gpr_malloc(query_parts.count * sizeof(char *));
-  uri->query_parts_values = gpr_malloc(query_parts.count * sizeof(char *));
-  uri->num_query_parts = query_parts.count;
-  for (size_t i = 0; i < query_parts.count; i++) {
-    grpc_slice_split(query_parts.slices[i], QUERY_PARTS_VALUE_SEPARATOR,
-                     &query_param_parts);
-    GPR_ASSERT(query_param_parts.count > 0);
-    uri->query_parts[i] =
-        grpc_dump_slice(query_param_parts.slices[0], GPR_DUMP_ASCII);
-    if (query_param_parts.count > 1) {
+  gpr_string_split(uri->query, QUERY_PARTS_SEPARATOR, &uri->query_parts,
+                   &uri->num_query_parts);
+  uri->query_parts_values = gpr_malloc(uri->num_query_parts * sizeof(char **));
+  for (size_t i = 0; i < uri->num_query_parts; i++) {
+    char **query_param_parts;
+    size_t num_query_param_parts;
+    char *full = uri->query_parts[i];
+    gpr_string_split(full, QUERY_PARTS_VALUE_SEPARATOR, &query_param_parts,
+                     &num_query_param_parts);
+    GPR_ASSERT(num_query_param_parts > 0);
+    uri->query_parts[i] = query_param_parts[0];
+    if (num_query_param_parts > 1) {
       /* TODO(dgq): only the first value after the separator is considered.
        * Perhaps all chars after the first separator for the query part should
        * be included, even if they include the separator. */
-      uri->query_parts_values[i] =
-          grpc_dump_slice(query_param_parts.slices[1], GPR_DUMP_ASCII);
+      uri->query_parts_values[i] = query_param_parts[1];
     } else {
       uri->query_parts_values[i] = NULL;
     }
-    grpc_slice_buffer_reset_and_unref(&query_param_parts);
+    for (size_t j = 2; j < num_query_param_parts; j++) {
+      gpr_free(query_param_parts[j]);
+    }
+    gpr_free(query_param_parts);
+    gpr_free(full);
   }
-  grpc_slice_buffer_destroy(&query_parts);
-  grpc_slice_buffer_destroy(&query_param_parts);
-  grpc_slice_unref(query_slice);
 }
 
 grpc_uri *grpc_uri_parse(const char *uri_text, int suppress_errors) {
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
index df0db61..97f98df 100644
--- a/src/core/ext/lb_policy/grpclb/grpclb.c
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -106,6 +106,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
+#include "src/core/ext/client_channel/client_channel.h"
 #include "src/core/ext/client_channel/client_channel_factory.h"
 #include "src/core/ext/client_channel/lb_policy_factory.h"
 #include "src/core/ext/client_channel/lb_policy_registry.h"
@@ -116,6 +117,7 @@
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/backoff.h"
 #include "src/core/lib/support/string.h"
@@ -179,8 +181,7 @@
   wrapped_rr_closure_arg *wc_arg = arg;
 
   GPR_ASSERT(wc_arg->wrapped_closure != NULL);
-  grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error),
-                      NULL);
+  grpc_closure_sched(exec_ctx, wc_arg->wrapped_closure, GRPC_ERROR_REF(error));
 
   if (wc_arg->rr_policy != NULL) {
     /* if *target is NULL, no pick has been made by the RR policy (eg, all
@@ -247,7 +248,8 @@
       pick_args->lb_token_mdelem_storage;
   pp->wrapped_on_complete_arg.free_when_done = pp;
   grpc_closure_init(&pp->wrapped_on_complete_arg.wrapper_closure,
-                    wrapped_rr_closure, &pp->wrapped_on_complete_arg);
+                    wrapped_rr_closure, &pp->wrapped_on_complete_arg,
+                    grpc_schedule_on_exec_ctx);
   *root = pp;
 }
 
@@ -267,7 +269,8 @@
   pping->wrapped_notify_arg.free_when_done = pping;
   pping->next = *root;
   grpc_closure_init(&pping->wrapped_notify_arg.wrapper_closure,
-                    wrapped_rr_closure, &pping->wrapped_notify_arg);
+                    wrapped_rr_closure, &pping->wrapped_notify_arg,
+                    grpc_schedule_on_exec_ctx);
   *root = pping;
 }
 
@@ -324,6 +327,9 @@
   /* A response from the LB server has been received. Process it */
   grpc_closure lb_on_response_received;
 
+  /* LB call retry timer callback. */
+  grpc_closure lb_on_call_retry;
+
   grpc_call *lb_call; /* streaming call to the LB server, */
 
   grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */
@@ -384,8 +390,8 @@
 static void *lb_token_copy(void *token) {
   return token == NULL ? NULL : GRPC_MDELEM_REF(token);
 }
-static void lb_token_destroy(void *token) {
-  if (token != NULL) GRPC_MDELEM_UNREF(token);
+static void lb_token_destroy(grpc_exec_ctx *exec_ctx, void *token) {
+  if (token != NULL) GRPC_MDELEM_UNREF(exec_ctx, token);
 }
 static int lb_token_cmp(void *token1, void *token2) {
   if (token1 > token2) return 1;
@@ -419,7 +425,7 @@
 
 /* Returns addresses extracted from \a serverlist. */
 static grpc_lb_addresses *process_serverlist_locked(
-    const grpc_grpclb_serverlist *serverlist) {
+    grpc_exec_ctx *exec_ctx, const grpc_grpclb_serverlist *serverlist) {
   size_t num_valid = 0;
   /* first pass: count how many are valid in order to allocate the necessary
    * memory in a single block */
@@ -455,8 +461,8 @@
           strnlen(server->load_balance_token, lb_token_max_length);
       grpc_mdstr *lb_token_mdstr = grpc_mdstr_from_buffer(
           (uint8_t *)server->load_balance_token, lb_token_length);
-      user_data = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_LB_TOKEN,
-                                                    lb_token_mdstr);
+      user_data = grpc_mdelem_from_metadata_strings(
+          exec_ctx, GRPC_MDSTR_LB_TOKEN, lb_token_mdstr);
     } else {
       char *uri = grpc_sockaddr_to_uri(&addr);
       gpr_log(GPR_INFO,
@@ -579,7 +585,8 @@
   grpc_lb_policy_args args;
   memset(&args, 0, sizeof(args));
   args.client_channel_factory = glb_policy->cc_factory;
-  grpc_lb_addresses *addresses = process_serverlist_locked(serverlist);
+  grpc_lb_addresses *addresses =
+      process_serverlist_locked(exec_ctx, serverlist);
 
   // Replace the LB addresses in the channel args that we pass down to
   // the subchannel.
@@ -591,8 +598,8 @@
 
   grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args);
   GPR_ASSERT(rr != NULL);
-  grpc_lb_addresses_destroy(addresses);
-  grpc_channel_args_destroy(args.args);
+  grpc_lb_addresses_destroy(exec_ctx, addresses);
+  grpc_channel_args_destroy(exec_ctx, args.args);
   return rr;
 }
 
@@ -666,7 +673,7 @@
       gpr_malloc(sizeof(rr_connectivity_data));
   memset(rr_connectivity, 0, sizeof(rr_connectivity_data));
   grpc_closure_init(&rr_connectivity->on_change, glb_rr_connectivity_changed,
-                    rr_connectivity);
+                    rr_connectivity, grpc_schedule_on_exec_ctx);
   rr_connectivity->glb_policy = glb_policy;
   rr_connectivity->state = new_rr_state;
 
@@ -743,12 +750,6 @@
 static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
                                   grpc_lb_policy_factory *factory,
                                   grpc_lb_policy_args *args) {
-  /* Get server name. */
-  const grpc_arg *arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME);
-  const char *server_name =
-      arg != NULL && arg->type == GRPC_ARG_STRING ? arg->value.string : NULL;
-
   /* Count the number of gRPC-LB addresses. There must be at least one.
    * TODO(roth): For now, we ignore non-balancer addresses, but in the
    * future, we may change the behavior such that we fall back to using
@@ -756,7 +757,8 @@
    * time, this should be changed to allow a list with no balancer addresses,
    * since the resolver might fail to return a balancer address even when
    * this is the right LB policy to use. */
-  arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
+  const grpc_arg *arg =
+      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
   GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
   grpc_lb_addresses *addresses = arg->value.pointer.p;
   size_t num_grpclb_addrs = 0;
@@ -768,13 +770,25 @@
   glb_lb_policy *glb_policy = gpr_malloc(sizeof(*glb_policy));
   memset(glb_policy, 0, sizeof(*glb_policy));
 
+  /* Get server name. */
+  arg = grpc_channel_args_find(args->args, GRPC_ARG_SERVER_URI);
+  GPR_ASSERT(arg != NULL);
+  GPR_ASSERT(arg->type == GRPC_ARG_STRING);
+  grpc_uri *uri = grpc_uri_parse(arg->value.string, true);
+  GPR_ASSERT(uri->path[0] != '\0');
+  glb_policy->server_name =
+      gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path);
+  if (grpc_lb_glb_trace) {
+    gpr_log(GPR_INFO, "Will use '%s' as the server name for LB request.",
+            glb_policy->server_name);
+  }
+  grpc_uri_destroy(uri);
+
   /* All input addresses in addresses come from a resolver that claims
    * they are LB services. It's the resolver's responsibility to make sure
-   * this
-   * policy is only instantiated and used in that case.
+   * this policy is only instantiated and used in that case.
    *
    * Create a client channel over them to communicate with a LB service */
-  glb_policy->server_name = gpr_strdup(server_name);
   glb_policy->cc_factory = args->client_channel_factory;
   glb_policy->args = grpc_channel_args_copy(args->args);
   GPR_ASSERT(glb_policy->cc_factory != NULL);
@@ -818,15 +832,20 @@
    * We need the LB channel to return addresses with is_balancer=false
    * so that it does not wind up recursively using the grpclb LB policy,
    * as per the special case logic in client_channel.c.
+   *
+   * Finally, we also strip out the channel arg for the server URI,
+   * since that will be different for the LB channel than for the parent
+   * channel.  (The client channel factory will re-add this arg with
+   * the right value.)
    */
-  static const char *keys_to_remove[] = {GRPC_ARG_LB_POLICY_NAME,
-                                         GRPC_ARG_LB_ADDRESSES};
+  static const char *keys_to_remove[] = {
+      GRPC_ARG_LB_POLICY_NAME, GRPC_ARG_LB_ADDRESSES, GRPC_ARG_SERVER_URI};
   grpc_channel_args *new_args = grpc_channel_args_copy_and_remove(
       args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove));
   glb_policy->lb_channel = grpc_client_channel_factory_create_channel(
       exec_ctx, glb_policy->cc_factory, target_uri_str,
       GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, new_args);
-  grpc_channel_args_destroy(new_args);
+  grpc_channel_args_destroy(exec_ctx, new_args);
 
   gpr_free(target_uri_str);
   for (size_t i = 0; i < num_grpclb_addrs; i++) {
@@ -852,7 +871,7 @@
   GPR_ASSERT(glb_policy->pending_picks == NULL);
   GPR_ASSERT(glb_policy->pending_pings == NULL);
   gpr_free((void *)glb_policy->server_name);
-  grpc_channel_args_destroy(glb_policy->args);
+  grpc_channel_args_destroy(exec_ctx, glb_policy->args);
   grpc_channel_destroy(glb_policy->lb_channel);
   glb_policy->lb_channel = NULL;
   grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker);
@@ -895,15 +914,15 @@
   while (pp != NULL) {
     pending_pick *next = pp->next;
     *pp->target = NULL;
-    grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
-                        GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
+                       GRPC_ERROR_NONE);
     pp = next;
   }
 
   while (pping != NULL) {
     pending_ping *next = pping->next;
-    grpc_exec_ctx_sched(exec_ctx, &pping->wrapped_notify_arg.wrapper_closure,
-                        GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, &pping->wrapped_notify_arg.wrapper_closure,
+                       GRPC_ERROR_NONE);
     pping = next;
   }
 }
@@ -919,9 +938,9 @@
     pending_pick *next = pp->next;
     if (pp->target == target) {
       *target = NULL;
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
-          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL);
+          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
     } else {
       pp->next = glb_policy->pending_picks;
       glb_policy->pending_picks = pp;
@@ -944,9 +963,9 @@
     pending_pick *next = pp->next;
     if ((pp->pick_args.initial_metadata_flags & initial_metadata_flags_mask) ==
         initial_metadata_flags_eq) {
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, &pp->wrapped_on_complete_arg.wrapper_closure,
-          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL);
+          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
     } else {
       pp->next = glb_policy->pending_picks;
       glb_policy->pending_picks = pp;
@@ -981,11 +1000,10 @@
                     grpc_closure *on_complete) {
   if (pick_args->lb_token_mdelem_storage == NULL) {
     *target = NULL;
-    grpc_exec_ctx_sched(
+    grpc_closure_sched(
         exec_ctx, on_complete,
         GRPC_ERROR_CREATE("No mdelem storage for the LB token. Load reporting "
-                          "won't work without it. Failing"),
-        NULL);
+                          "won't work without it. Failing"));
     return 0;
   }
 
@@ -1004,7 +1022,8 @@
     wrapped_rr_closure_arg *wc_arg = gpr_malloc(sizeof(wrapped_rr_closure_arg));
     memset(wc_arg, 0, sizeof(wrapped_rr_closure_arg));
 
-    grpc_closure_init(&wc_arg->wrapper_closure, wrapped_rr_closure, wc_arg);
+    grpc_closure_init(&wc_arg->wrapper_closure, wrapped_rr_closure, wc_arg,
+                      grpc_schedule_on_exec_ctx);
     wc_arg->rr_policy = glb_policy->rr_policy;
     wc_arg->target = target;
     wc_arg->wrapped_closure = on_complete;
@@ -1075,7 +1094,8 @@
                                          grpc_error *error);
 static void lb_on_response_received(grpc_exec_ctx *exec_ctx, void *arg,
                                     grpc_error *error);
-static void lb_call_init_locked(glb_lb_policy *glb_policy) {
+static void lb_call_init_locked(grpc_exec_ctx *exec_ctx,
+                                glb_lb_policy *glb_policy) {
   GPR_ASSERT(glb_policy->server_name != NULL);
   GPR_ASSERT(glb_policy->server_name[0] != '\0');
   GPR_ASSERT(!glb_policy->shutting_down);
@@ -1084,7 +1104,7 @@
    * glb_policy->base.interested_parties, which is comprised of the polling
    * entities from \a client_channel. */
   glb_policy->lb_call = grpc_channel_create_pollset_set_call(
-      glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+      exec_ctx, glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
       glb_policy->base.interested_parties,
       "/grpc.lb.v1.LoadBalancer/BalanceLoad", glb_policy->server_name,
       glb_policy->deadline, NULL);
@@ -1097,16 +1117,18 @@
   grpc_slice request_payload_slice = grpc_grpclb_request_encode(request);
   glb_policy->lb_request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  grpc_slice_unref(request_payload_slice);
+  grpc_slice_unref_internal(exec_ctx, request_payload_slice);
   grpc_grpclb_request_destroy(request);
 
   glb_policy->lb_call_status_details = NULL;
   glb_policy->lb_call_status_details_capacity = 0;
 
   grpc_closure_init(&glb_policy->lb_on_server_status_received,
-                    lb_on_server_status_received, glb_policy);
+                    lb_on_server_status_received, glb_policy,
+                    grpc_schedule_on_exec_ctx);
   grpc_closure_init(&glb_policy->lb_on_response_received,
-                    lb_on_response_received, glb_policy);
+                    lb_on_response_received, glb_policy,
+                    grpc_schedule_on_exec_ctx);
 
   gpr_backoff_init(&glb_policy->lb_call_backoff_state,
                    GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
@@ -1136,7 +1158,7 @@
   GPR_ASSERT(glb_policy->lb_channel != NULL);
   if (glb_policy->shutting_down) return;
 
-  lb_call_init_locked(glb_policy);
+  lb_call_init_locked(exec_ctx, glb_policy);
 
   if (grpc_lb_glb_trace) {
     gpr_log(GPR_INFO, "Query for backends (grpclb: %p, lb_call: %p)",
@@ -1221,7 +1243,7 @@
         grpc_grpclb_response_parse_serverlist(response_slice);
     if (serverlist != NULL) {
       GPR_ASSERT(glb_policy->lb_call != NULL);
-      grpc_slice_unref(response_slice);
+      grpc_slice_unref_internal(exec_ctx, response_slice);
       if (grpc_lb_glb_trace) {
         gpr_log(GPR_INFO, "Serverlist with %lu servers received",
                 (unsigned long)serverlist->num_servers);
@@ -1265,7 +1287,7 @@
     } else { /* serverlist == NULL */
       gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.",
               grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX));
-      grpc_slice_unref(response_slice);
+      grpc_slice_unref_internal(exec_ctx, response_slice);
     }
 
     if (!glb_policy->shutting_down) {
@@ -1345,8 +1367,10 @@
       }
     }
     GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer");
+    grpc_closure_init(&glb_policy->lb_on_call_retry, lb_call_on_retry_timer,
+                      glb_policy, grpc_schedule_on_exec_ctx);
     grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try,
-                    lb_call_on_retry_timer, glb_policy, now);
+                    &glb_policy->lb_on_call_retry, now);
   }
   gpr_mu_unlock(&glb_policy->mu);
   GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
diff --git a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
index afecb71..e352e03 100644
--- a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
+++ b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c
@@ -1,35 +1,3 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
 /* Automatically generated nanopb constant definitions */
 /* Generated by nanopb-0.3.7-dev */
 
diff --git a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
index e36d096..725aa7e 100644
--- a/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
+++ b/src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h
@@ -1,35 +1,3 @@
-/*
- *
- * Copyright 2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
 /* Automatically generated nanopb header */
 /* Generated by nanopb-0.3.7-dev */
 
diff --git a/src/core/ext/lb_policy/pick_first/pick_first.c b/src/core/ext/lb_policy/pick_first/pick_first.c
index c69f773..821becf 100644
--- a/src/core/ext/lb_policy/pick_first/pick_first.c
+++ b/src/core/ext/lb_policy/pick_first/pick_first.c
@@ -120,7 +120,7 @@
   while (pp != NULL) {
     pending_pick *next = pp->next;
     *pp->target = NULL;
-    grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
     gpr_free(pp);
     pp = next;
   }
@@ -138,9 +138,9 @@
     pending_pick *next = pp->next;
     if (pp->target == target) {
       *target = NULL;
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, pp->on_complete,
-          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL);
+          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
       gpr_free(pp);
     } else {
       pp->next = p->pending_picks;
@@ -165,9 +165,9 @@
     pending_pick *next = pp->next;
     if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
         initial_metadata_flags_eq) {
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, pp->on_complete,
-          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL);
+          GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1));
       gpr_free(pp);
     } else {
       pp->next = p->pending_picks;
@@ -306,14 +306,15 @@
         /* drop the pick list: we are connected now */
         GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
         gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
-        grpc_exec_ctx_sched(exec_ctx,
-                            grpc_closure_create(destroy_subchannels, p),
-                            GRPC_ERROR_NONE, NULL);
+        grpc_closure_sched(exec_ctx,
+                           grpc_closure_create(destroy_subchannels, p,
+                                               grpc_schedule_on_exec_ctx),
+                           GRPC_ERROR_NONE);
         /* update any calls that were waiting for a pick */
         while ((pp = p->pending_picks)) {
           p->pending_picks = pp->next;
           *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked");
-          grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
+          grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
           gpr_free(pp);
         }
         grpc_connected_subchannel_notify_on_state_change(
@@ -366,8 +367,7 @@
           while ((pp = p->pending_picks)) {
             p->pending_picks = pp->next;
             *pp->target = NULL;
-            grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE,
-                                NULL);
+            grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
             gpr_free(pp);
           }
           GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
@@ -419,8 +419,7 @@
   if (selected) {
     grpc_connected_subchannel_ping(exec_ctx, selected, closure);
   } else {
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected"));
   }
 }
 
@@ -438,15 +437,10 @@
                                          grpc_lb_policy_args *args) {
   GPR_ASSERT(args->client_channel_factory != NULL);
 
-  /* Get server name. */
-  const grpc_arg *arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME);
-  const char *server_name =
-      arg != NULL && arg->type == GRPC_ARG_STRING ? arg->value.string : NULL;
-
   /* Find the number of backend addresses. We ignore balancer
    * addresses, since we don't know how to handle them. */
-  arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
+  const grpc_arg *arg =
+      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
   GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
   grpc_lb_addresses *addresses = arg->value.pointer.p;
   size_t num_addrs = 0;
@@ -472,9 +466,6 @@
     }
 
     memset(&sc_args, 0, sizeof(grpc_subchannel_args));
-    /* server_name will be copied as part of the subchannel creation. This makes
-     * the copying of server_name (a borrowed pointer) OK. */
-    sc_args.server_name = server_name;
     sc_args.addr = &addresses->addresses[i].address;
     sc_args.args = args->args;
 
@@ -493,7 +484,8 @@
   p->num_subchannels = subchannel_idx;
 
   grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
-  grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
+  grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p,
+                    grpc_schedule_on_exec_ctx);
   gpr_mu_init(&p->mu);
   return &p->base;
 }
diff --git a/src/core/ext/lb_policy/round_robin/round_robin.c b/src/core/ext/lb_policy/round_robin/round_robin.c
index 59f8405..cb67948 100644
--- a/src/core/ext/lb_policy/round_robin/round_robin.c
+++ b/src/core/ext/lb_policy/round_robin/round_robin.c
@@ -284,7 +284,7 @@
     GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_destroy");
     if (sd->user_data != NULL) {
       GPR_ASSERT(sd->user_data_vtable != NULL);
-      sd->user_data_vtable->destroy(sd->user_data);
+      sd->user_data_vtable->destroy(exec_ctx, sd->user_data);
     }
     gpr_free(sd);
   }
@@ -321,8 +321,8 @@
   while ((pp = p->pending_picks)) {
     p->pending_picks = pp->next;
     *pp->target = NULL;
-    grpc_exec_ctx_sched(exec_ctx, pp->on_complete,
-                        GRPC_ERROR_CREATE("Channel Shutdown"), NULL);
+    grpc_closure_sched(exec_ctx, pp->on_complete,
+                       GRPC_ERROR_CREATE("Channel Shutdown"));
     gpr_free(pp);
   }
   grpc_connectivity_state_set(
@@ -348,9 +348,9 @@
     pending_pick *next = pp->next;
     if (pp->target == target) {
       *target = NULL;
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, pp->on_complete,
-          GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1), NULL);
+          GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
       gpr_free(pp);
     } else {
       pp->next = p->pending_picks;
@@ -376,9 +376,9 @@
     if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
         initial_metadata_flags_eq) {
       *pp->target = NULL;
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, pp->on_complete,
-          GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1), NULL);
+          GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
       gpr_free(pp);
     } else {
       pp->next = p->pending_picks;
@@ -581,7 +581,7 @@
                   "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
                   (void *)selected->subchannel, (void *)selected);
         }
-        grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
+        grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
         gpr_free(pp);
       }
       update_lb_connectivity_status(exec_ctx, sd, error);
@@ -634,7 +634,7 @@
         while ((pp = p->pending_picks)) {
           p->pending_picks = pp->next;
           *pp->target = NULL;
-          grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
+          grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
           gpr_free(pp);
         }
       }
@@ -684,8 +684,8 @@
     GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked");
   } else {
     gpr_mu_unlock(&p->mu);
-    grpc_exec_ctx_sched(exec_ctx, closure,
-                        GRPC_ERROR_CREATE("Round Robin not connected"), NULL);
+    grpc_closure_sched(exec_ctx, closure,
+                       GRPC_ERROR_CREATE("Round Robin not connected"));
   }
 }
 
@@ -703,15 +703,10 @@
                                           grpc_lb_policy_args *args) {
   GPR_ASSERT(args->client_channel_factory != NULL);
 
-  /* Get server name. */
-  const grpc_arg *arg =
-      grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME);
-  const char *server_name =
-      arg != NULL && arg->type == GRPC_ARG_STRING ? arg->value.string : NULL;
-
   /* Find the number of backend addresses. We ignore balancer
    * addresses, since we don't know how to handle them. */
-  arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
+  const grpc_arg *arg =
+      grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
   GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
   grpc_lb_addresses *addresses = arg->value.pointer.p;
   size_t num_addrs = 0;
@@ -734,9 +729,6 @@
     if (addresses->addresses[i].is_balancer) continue;
 
     memset(&sc_args, 0, sizeof(grpc_subchannel_args));
-    /* server_name will be copied as part of the subchannel creation. This makes
-     * the copying of server_name (a borrowed pointer) OK. */
-    sc_args.server_name = server_name;
     sc_args.addr = &addresses->addresses[i].address;
     sc_args.args = args->args;
 
@@ -757,7 +749,7 @@
       }
       ++subchannel_idx;
       grpc_closure_init(&sd->connectivity_changed_closure,
-                        rr_connectivity_changed, sd);
+                        rr_connectivity_changed, sd, grpc_schedule_on_exec_ctx);
     }
   }
   if (subchannel_idx == 0) {
diff --git a/src/core/ext/load_reporting/load_reporting.c b/src/core/ext/load_reporting/load_reporting.c
index df1ea0e..37b06a7 100644
--- a/src/core/ext/load_reporting/load_reporting.c
+++ b/src/core/ext/load_reporting/load_reporting.c
@@ -53,7 +53,8 @@
   return false;
 }
 
-static bool maybe_add_load_reporting_filter(grpc_channel_stack_builder *builder,
+static bool maybe_add_load_reporting_filter(grpc_exec_ctx *exec_ctx,
+                                            grpc_channel_stack_builder *builder,
                                             void *arg) {
   const grpc_channel_args *args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index b810e20..07ef10e 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -68,7 +68,8 @@
   grpc_exec_ctx *exec_ctx;
 } recv_md_filter_args;
 
-static grpc_mdelem *recv_md_filter(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *recv_md_filter(grpc_exec_ctx *exec_ctx, void *user_data,
+                                   grpc_mdelem *md) {
   recv_md_filter_args *a = user_data;
   grpc_call_element *elem = a->elem;
   call_data *calld = elem->call_data;
@@ -92,8 +93,8 @@
     recv_md_filter_args a;
     a.elem = elem;
     a.exec_ctx = exec_ctx;
-    grpc_metadata_batch_filter(calld->recv_initial_metadata, recv_md_filter,
-                               &a);
+    grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
+                               recv_md_filter, &a);
     if (calld->service_method == NULL) {
       err =
           grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header"));
@@ -114,7 +115,8 @@
   memset(calld, 0, sizeof(call_data));
 
   calld->id = (intptr_t)args->call_stack;
-  grpc_closure_init(&calld->on_initial_md_ready, on_initial_md_ready, elem);
+  grpc_closure_init(&calld->on_initial_md_ready, on_initial_md_ready, elem,
+                    grpc_schedule_on_exec_ctx);
 
   /* TODO(dgq): do something with the data
   channel_data *chand = elem->channel_data;
@@ -152,9 +154,9 @@
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   GPR_ASSERT(!args->is_last);
 
   channel_data *chand = elem->channel_data;
@@ -171,6 +173,8 @@
                                                 NULL,
                                                 NULL};
                                                 */
+
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel data */
@@ -189,7 +193,8 @@
   */
 }
 
-static grpc_mdelem *lr_trailing_md_filter(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *lr_trailing_md_filter(grpc_exec_ctx *exec_ctx,
+                                          void *user_data, grpc_mdelem *md) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
 
@@ -213,7 +218,7 @@
     calld->ops_recv_initial_metadata_ready = op->recv_initial_metadata_ready;
     op->recv_initial_metadata_ready = &calld->on_initial_md_ready;
   } else if (op->send_trailing_metadata) {
-    grpc_metadata_batch_filter(op->send_trailing_metadata,
+    grpc_metadata_batch_filter(exec_ctx, op->send_trailing_metadata,
                                lr_trailing_md_filter, elem);
   }
   grpc_call_next_op(exec_ctx, elem, op);
diff --git a/src/core/ext/resolver/README.md b/src/core/ext/resolver/README.md
new file mode 100644
index 0000000..b0e234e
--- /dev/null
+++ b/src/core/ext/resolver/README.md
@@ -0,0 +1,4 @@
+# Resolver
+
+Implementations of various name resolution schemes.
+See the [naming spec](/doc/naming.md).
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 15476f5..655d9dc 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -61,6 +61,8 @@
   char *default_port;
   /** channel args. */
   grpc_channel_args *channel_args;
+  /** pollset_set to drive the name resolution process */
+  grpc_pollset_set *interested_parties;
 
   /** mutex guarding the rest of the state */
   gpr_mu mu;
@@ -79,6 +81,7 @@
   /** retry timer */
   bool have_retry_timer;
   grpc_timer retry_timer;
+  grpc_closure on_retry;
   /** retry backoff state */
   gpr_backoff backoff_state;
 
@@ -110,8 +113,8 @@
   }
   if (r->next_completion != NULL) {
     *r->target_result = NULL;
-    grpc_exec_ctx_sched(exec_ctx, r->next_completion,
-                        GRPC_ERROR_CREATE("Resolver Shutdown"), NULL);
+    grpc_closure_sched(exec_ctx, r->next_completion,
+                       GRPC_ERROR_CREATE("Resolver Shutdown"));
     r->next_completion = NULL;
   }
   gpr_mu_unlock(&r->mu);
@@ -180,13 +183,13 @@
     grpc_arg new_arg = grpc_lb_addresses_create_channel_arg(addresses);
     result = grpc_channel_args_copy_and_add(r->channel_args, &new_arg, 1);
     grpc_resolved_addresses_destroy(r->addresses);
-    grpc_lb_addresses_destroy(addresses);
+    grpc_lb_addresses_destroy(exec_ctx, addresses);
   } else {
     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
     gpr_timespec next_try = gpr_backoff_step(&r->backoff_state, now);
     gpr_timespec timeout = gpr_time_sub(next_try, now);
     const char *msg = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
+    gpr_log(GPR_INFO, "dns resolution failed (will retry): %s", msg);
     grpc_error_free_string(msg);
     GPR_ASSERT(!r->have_retry_timer);
     r->have_retry_timer = true;
@@ -197,11 +200,12 @@
     } else {
       gpr_log(GPR_DEBUG, "retrying immediately");
     }
-    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
-                    now);
+    grpc_closure_init(&r->on_retry, dns_on_retry_timer, r,
+                      grpc_schedule_on_exec_ctx);
+    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry, now);
   }
   if (r->resolved_result != NULL) {
-    grpc_channel_args_destroy(r->resolved_result);
+    grpc_channel_args_destroy(exec_ctx, r->resolved_result);
   }
   r->resolved_result = result;
   r->resolved_version++;
@@ -217,8 +221,10 @@
   GPR_ASSERT(!r->resolving);
   r->resolving = true;
   r->addresses = NULL;
-  grpc_resolve_address(exec_ctx, r->name_to_resolve, r->default_port,
-                       grpc_closure_create(dns_on_resolved, r), &r->addresses);
+  grpc_resolve_address(
+      exec_ctx, r->name_to_resolve, r->default_port, r->interested_parties,
+      grpc_closure_create(dns_on_resolved, r, grpc_schedule_on_exec_ctx),
+      &r->addresses);
 }
 
 static void dns_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
@@ -228,7 +234,7 @@
     *r->target_result = r->resolved_result == NULL
                             ? NULL
                             : grpc_channel_args_copy(r->resolved_result);
-    grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
     r->published_version = r->resolved_version;
   }
@@ -238,15 +244,17 @@
   dns_resolver *r = (dns_resolver *)gr;
   gpr_mu_destroy(&r->mu);
   if (r->resolved_result != NULL) {
-    grpc_channel_args_destroy(r->resolved_result);
+    grpc_channel_args_destroy(exec_ctx, r->resolved_result);
   }
+  grpc_pollset_set_destroy(r->interested_parties);
   gpr_free(r->name_to_resolve);
   gpr_free(r->default_port);
-  grpc_channel_args_destroy(r->channel_args);
+  grpc_channel_args_destroy(exec_ctx, r->channel_args);
   gpr_free(r);
 }
 
-static grpc_resolver *dns_create(grpc_resolver_args *args,
+static grpc_resolver *dns_create(grpc_exec_ctx *exec_ctx,
+                                 grpc_resolver_args *args,
                                  const char *default_port) {
   if (0 != strcmp(args->uri->authority, "")) {
     gpr_log(GPR_ERROR, "authority based dns uri's not supported");
@@ -264,12 +272,12 @@
   grpc_resolver_init(&r->base, &dns_resolver_vtable);
   r->name_to_resolve = proxy_name == NULL ? gpr_strdup(path) : proxy_name;
   r->default_port = gpr_strdup(default_port);
-  grpc_arg server_name_arg;
-  server_name_arg.type = GRPC_ARG_STRING;
-  server_name_arg.key = GRPC_ARG_SERVER_NAME;
-  server_name_arg.value.string = (char *)path;
-  r->channel_args =
-      grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
+  r->channel_args = grpc_channel_args_copy(args->args);
+  r->interested_parties = grpc_pollset_set_create();
+  if (args->pollset_set != NULL) {
+    grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
+                                     args->pollset_set);
+  }
   gpr_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
                    GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
                    GRPC_DNS_RECONNECT_JITTER,
@@ -287,8 +295,9 @@
 static void dns_factory_unref(grpc_resolver_factory *factory) {}
 
 static grpc_resolver *dns_factory_create_resolver(
-    grpc_resolver_factory *factory, grpc_resolver_args *args) {
-  return dns_create(args, "https");
+    grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory,
+    grpc_resolver_args *args) {
+  return dns_create(exec_ctx, args, "https");
 }
 
 static char *dns_factory_get_default_host_name(grpc_resolver_factory *factory,
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index 26a650a..c146a62 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -47,6 +47,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
@@ -89,7 +90,7 @@
   gpr_mu_lock(&r->mu);
   if (r->next_completion != NULL) {
     *r->target_result = NULL;
-    grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
   }
   gpr_mu_unlock(&r->mu);
@@ -123,7 +124,7 @@
     grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
     *r->target_result =
         grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
-    grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
   }
 }
@@ -131,8 +132,8 @@
 static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
   sockaddr_resolver *r = (sockaddr_resolver *)gr;
   gpr_mu_destroy(&r->mu);
-  grpc_lb_addresses_destroy(r->addresses);
-  grpc_channel_args_destroy(r->channel_args);
+  grpc_lb_addresses_destroy(exec_ctx, r->addresses);
+  grpc_channel_args_destroy(exec_ctx, r->channel_args);
   gpr_free(r);
 }
 
@@ -161,7 +162,8 @@
 
 static void do_nothing(void *ignored) {}
 
-static grpc_resolver *sockaddr_create(grpc_resolver_args *args,
+static grpc_resolver *sockaddr_create(grpc_exec_ctx *exec_ctx,
+                                      grpc_resolver_args *args,
                                       int parse(grpc_uri *uri,
                                                 grpc_resolved_address *dst)) {
   if (0 != strcmp(args->uri->authority, "")) {
@@ -188,22 +190,17 @@
     gpr_free(part_str);
     if (errors_found) break;
   }
-  grpc_slice_buffer_destroy(&path_parts);
-  grpc_slice_unref(path_slice);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &path_parts);
+  grpc_slice_unref_internal(exec_ctx, path_slice);
   if (errors_found) {
-    grpc_lb_addresses_destroy(addresses);
+    grpc_lb_addresses_destroy(exec_ctx, addresses);
     return NULL;
   }
   /* Instantiate resolver. */
   sockaddr_resolver *r = gpr_malloc(sizeof(sockaddr_resolver));
   memset(r, 0, sizeof(*r));
   r->addresses = addresses;
-  grpc_arg server_name_arg;
-  server_name_arg.type = GRPC_ARG_STRING;
-  server_name_arg.key = GRPC_ARG_SERVER_NAME;
-  server_name_arg.value.string = args->uri->path;
-  r->channel_args =
-      grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
+  r->channel_args = grpc_channel_args_copy(args->args);
   gpr_mu_init(&r->mu);
   grpc_resolver_init(&r->base, &sockaddr_resolver_vtable);
   return &r->base;
@@ -219,8 +216,9 @@
 
 #define DECL_FACTORY(name)                                                  \
   static grpc_resolver *name##_factory_create_resolver(                     \
-      grpc_resolver_factory *factory, grpc_resolver_args *args) {           \
-    return sockaddr_create(args, parse_##name);                             \
+      grpc_exec_ctx *exec_ctx, grpc_resolver_factory *factory,              \
+      grpc_resolver_args *args) {                                           \
+    return sockaddr_create(exec_ctx, args, parse_##name);                   \
   }                                                                         \
   static const grpc_resolver_factory_vtable name##_factory_vtable = {       \
       sockaddr_factory_ref, sockaddr_factory_unref,                         \
diff --git a/src/core/ext/transport/README.md b/src/core/ext/transport/README.md
new file mode 100644
index 0000000..2290568
--- /dev/null
+++ b/src/core/ext/transport/README.md
@@ -0,0 +1 @@
+Transports for gRPC
diff --git a/src/core/ext/transport/chttp2/README.md b/src/core/ext/transport/chttp2/README.md
new file mode 100644
index 0000000..8880a47
--- /dev/null
+++ b/src/core/ext/transport/chttp2/README.md
@@ -0,0 +1 @@
+CHTTP2 - gRPC's implementation of a HTTP2 based transport
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.c b/src/core/ext/transport/chttp2/client/chttp2_connector.c
index 58a6877..2c5dfae 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.c
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.c
@@ -46,8 +46,9 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/iomgr/tcp_client.h"
-#include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/slice/slice_internal.h"
 
 typedef struct {
   grpc_connector base;
@@ -58,10 +59,6 @@
   bool shutdown;
   bool connecting;
 
-  char *server_name;
-  grpc_chttp2_add_handshakers_func add_handshakers;
-  void *add_handshakers_user_data;
-
   grpc_closure *notify;
   grpc_connect_in_args args;
   grpc_connect_out_args *result;
@@ -89,7 +86,6 @@
     // If handshaking is not yet in progress, destroy the endpoint.
     // Otherwise, the handshaker will do this for us.
     if (c->endpoint != NULL) grpc_endpoint_destroy(exec_ctx, c->endpoint);
-    gpr_free(c->server_name);
     gpr_free(c);
   }
 }
@@ -126,8 +122,8 @@
       // point this can be removed.
       grpc_endpoint_shutdown(exec_ctx, args->endpoint);
       grpc_endpoint_destroy(exec_ctx, args->endpoint);
-      grpc_channel_args_destroy(args->args);
-      grpc_slice_buffer_destroy(args->read_buffer);
+      grpc_channel_args_destroy(exec_ctx, args->args);
+      grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer);
       gpr_free(args->read_buffer);
     } else {
       error = GRPC_ERROR_REF(error);
@@ -143,7 +139,7 @@
   }
   grpc_closure *notify = c->notify;
   c->notify = NULL;
-  grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
+  grpc_closure_sched(exec_ctx, notify, error);
   grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
   c->handshake_mgr = NULL;
   gpr_mu_unlock(&c->mu);
@@ -153,17 +149,8 @@
 static void start_handshake_locked(grpc_exec_ctx *exec_ctx,
                                    chttp2_connector *c) {
   c->handshake_mgr = grpc_handshake_manager_create();
-  char *proxy_name = grpc_get_http_proxy_server();
-  if (proxy_name != NULL) {
-    grpc_handshake_manager_add(
-        c->handshake_mgr,
-        grpc_http_connect_handshaker_create(proxy_name, c->server_name));
-    gpr_free(proxy_name);
-  }
-  if (c->add_handshakers != NULL) {
-    c->add_handshakers(exec_ctx, c->add_handshakers_user_data,
+  grpc_handshakers_add(exec_ctx, HANDSHAKER_CLIENT, c->args.channel_args,
                        c->handshake_mgr);
-  }
   grpc_handshake_manager_do_handshake(
       exec_ctx, c->handshake_mgr, c->endpoint, c->args.channel_args,
       c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
@@ -183,7 +170,7 @@
     memset(c->result, 0, sizeof(*c->result));
     grpc_closure *notify = c->notify;
     c->notify = NULL;
-    grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
+    grpc_closure_sched(exec_ctx, notify, error);
     gpr_mu_unlock(&c->mu);
     chttp2_connector_unref(exec_ctx, arg);
   } else {
@@ -206,7 +193,7 @@
     memset(c->result, 0, sizeof(*c->result));
     grpc_closure *notify = c->notify;
     c->notify = NULL;
-    grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
+    grpc_closure_sched(exec_ctx, notify, error);
     if (c->endpoint != NULL) grpc_endpoint_shutdown(exec_ctx, c->endpoint);
     gpr_mu_unlock(&c->mu);
     chttp2_connector_unref(exec_ctx, arg);
@@ -214,7 +201,7 @@
     GPR_ASSERT(c->endpoint != NULL);
     if (!GRPC_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
       grpc_closure_init(&c->initial_string_sent, on_initial_connect_string_sent,
-                        c);
+                        c, grpc_schedule_on_exec_ctx);
       grpc_slice_buffer_init(&c->initial_string_buffer);
       grpc_slice_buffer_add(&c->initial_string_buffer,
                             c->args.initial_connect_string);
@@ -240,7 +227,7 @@
   c->result = result;
   GPR_ASSERT(c->endpoint == NULL);
   chttp2_connector_ref(con);  // Ref taken for callback.
-  grpc_closure_init(&c->connected, connected, c);
+  grpc_closure_init(&c->connected, connected, c, grpc_schedule_on_exec_ctx);
   GPR_ASSERT(!c->connecting);
   c->connecting = true;
   grpc_tcp_client_connect(exec_ctx, &c->connected, &c->endpoint,
@@ -253,17 +240,11 @@
     chttp2_connector_ref, chttp2_connector_unref, chttp2_connector_shutdown,
     chttp2_connector_connect};
 
-grpc_connector *grpc_chttp2_connector_create(
-    grpc_exec_ctx *exec_ctx, const char *server_name,
-    grpc_chttp2_add_handshakers_func add_handshakers,
-    void *add_handshakers_user_data) {
+grpc_connector *grpc_chttp2_connector_create() {
   chttp2_connector *c = gpr_malloc(sizeof(*c));
   memset(c, 0, sizeof(*c));
   c->base.vtable = &chttp2_connector_vtable;
   gpr_mu_init(&c->mu);
   gpr_ref_init(&c->refs, 1);
-  c->server_name = gpr_strdup(server_name);
-  c->add_handshakers = add_handshakers;
-  c->add_handshakers_user_data = add_handshakers_user_data;
   return &c->base;
 }
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.h b/src/core/ext/transport/chttp2/client/chttp2_connector.h
index c57fb1a..f5d1025 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.h
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.h
@@ -35,18 +35,7 @@
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 
 #include "src/core/ext/client_channel/connector.h"
-#include "src/core/lib/channel/handshaker.h"
-#include "src/core/lib/iomgr/exec_ctx.h"
 
-typedef void (*grpc_chttp2_add_handshakers_func)(
-    grpc_exec_ctx* exec_ctx, void* user_data,
-    grpc_handshake_manager* handshake_mgr);
-
-/// If \a add_handshakers is non-NULL, it will be called with
-/// \a add_handshakers_user_data to add handshakers.
-grpc_connector* grpc_chttp2_connector_create(
-    grpc_exec_ctx* exec_ctx, const char* server_name,
-    grpc_chttp2_add_handshakers_func add_handshakers,
-    void* add_handshakers_user_data);
+grpc_connector* grpc_chttp2_connector_create();
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H */
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create.c b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
index 89501c5..c9f4021 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -39,8 +39,8 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/channel.h"
 
@@ -53,9 +53,7 @@
 static grpc_subchannel *client_channel_factory_create_subchannel(
     grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
     const grpc_subchannel_args *args) {
-  grpc_connector *connector = grpc_chttp2_connector_create(
-      exec_ctx, args->server_name, NULL /* add_handshakers */,
-      NULL /* user_data */);
+  grpc_connector *connector = grpc_chttp2_connector_create();
   grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
   grpc_connector_unref(exec_ctx, connector);
   return s;
@@ -65,17 +63,15 @@
     grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
     const char *target, grpc_client_channel_type type,
     const grpc_channel_args *args) {
-  grpc_channel *channel =
-      grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
-  grpc_resolver *resolver = grpc_resolver_create(target, args);
-  if (resolver == NULL) {
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
-                                "client_channel_factory_create_channel");
-    return NULL;
-  }
-  grpc_client_channel_finish_initialization(
-      exec_ctx, grpc_channel_get_channel_stack(channel), resolver, cc_factory);
-  GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
+  // Add channel arg containing the server URI.
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = GRPC_ARG_SERVER_URI;
+  arg.value.string = (char *)target;
+  grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
+  grpc_channel *channel = grpc_channel_create(exec_ctx, target, new_args,
+                                              GRPC_CLIENT_CHANNEL, NULL);
+  grpc_channel_args_destroy(exec_ctx, new_args);
   return channel;
 }
 
@@ -99,11 +95,16 @@
       "grpc_insecure_channel_create(target=%p, args=%p, reserved=%p)", 3,
       (target, args, reserved));
   GPR_ASSERT(reserved == NULL);
-  grpc_client_channel_factory *factory =
-      (grpc_client_channel_factory *)&client_channel_factory;
+  // Add channel arg containing the client channel factory.
+  grpc_arg arg =
+      grpc_client_channel_factory_create_channel_arg(&client_channel_factory);
+  grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
+  // Create channel.
   grpc_channel *channel = client_channel_factory_create_channel(
-      &exec_ctx, factory, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, args);
-  grpc_client_channel_factory_unref(&exec_ctx, factory);
+      &exec_ctx, &client_channel_factory, target,
+      GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args);
+  // Clean up.
+  grpc_channel_args_destroy(&exec_ctx, new_args);
   grpc_exec_ctx_finish(&exec_ctx);
   return channel != NULL ? channel : grpc_lame_client_channel_create(
                                          target, GRPC_STATUS_INTERNAL,
diff --git a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
index 1e5b1c2..f1069e2 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
@@ -74,7 +74,7 @@
   GPR_ASSERT(transport);
   grpc_channel *channel = grpc_channel_create(
       &exec_ctx, target, final_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
-  grpc_channel_args_destroy(final_args);
+  grpc_channel_args_destroy(&exec_ctx, final_args);
   grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
 
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
index 4bce3ba..f979d9b 100644
--- a/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
+++ b/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c
@@ -39,7 +39,6 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/client_channel/client_channel.h"
-#include "src/core/ext/client_channel/resolver_registry.h"
 #include "src/core/ext/transport/chttp2/client/chttp2_connector.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/security/credentials/credentials.h"
@@ -47,40 +46,16 @@
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/channel.h"
 
-typedef struct {
-  grpc_client_channel_factory base;
-  gpr_refcount refs;
-  grpc_channel_security_connector *security_connector;
-} client_channel_factory;
-
 static void client_channel_factory_ref(
-    grpc_client_channel_factory *cc_factory) {
-  client_channel_factory *f = (client_channel_factory *)cc_factory;
-  gpr_ref(&f->refs);
-}
+    grpc_client_channel_factory *cc_factory) {}
 
 static void client_channel_factory_unref(
-    grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory) {
-  client_channel_factory *f = (client_channel_factory *)cc_factory;
-  if (gpr_unref(&f->refs)) {
-    GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
-                                  "client_channel_factory");
-    gpr_free(f);
-  }
-}
-
-static void add_handshakers(grpc_exec_ctx *exec_ctx, void *security_connector,
-                            grpc_handshake_manager *handshake_mgr) {
-  grpc_channel_security_connector_add_handshakers(exec_ctx, security_connector,
-                                                  handshake_mgr);
-}
+    grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory) {}
 
 static grpc_subchannel *client_channel_factory_create_subchannel(
     grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
     const grpc_subchannel_args *args) {
-  client_channel_factory *f = (client_channel_factory *)cc_factory;
-  grpc_connector *connector = grpc_chttp2_connector_create(
-      exec_ctx, args->server_name, add_handshakers, f->security_connector);
+  grpc_connector *connector = grpc_chttp2_connector_create();
   grpc_subchannel *s = grpc_subchannel_create(exec_ctx, connector, args);
   grpc_connector_unref(exec_ctx, connector);
   return s;
@@ -90,18 +65,15 @@
     grpc_exec_ctx *exec_ctx, grpc_client_channel_factory *cc_factory,
     const char *target, grpc_client_channel_type type,
     const grpc_channel_args *args) {
-  client_channel_factory *f = (client_channel_factory *)cc_factory;
-  grpc_channel *channel =
-      grpc_channel_create(exec_ctx, target, args, GRPC_CLIENT_CHANNEL, NULL);
-  grpc_resolver *resolver = grpc_resolver_create(target, args);
-  if (resolver == NULL) {
-    GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel,
-                                "client_channel_factory_create_channel");
-    return NULL;
-  }
-  grpc_client_channel_finish_initialization(
-      exec_ctx, grpc_channel_get_channel_stack(channel), resolver, &f->base);
-  GRPC_RESOLVER_UNREF(exec_ctx, resolver, "create_channel");
+  // Add channel arg containing the server URI.
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = GRPC_ARG_SERVER_URI;
+  arg.value.string = (char *)target;
+  grpc_channel_args *new_args = grpc_channel_args_copy_and_add(args, &arg, 1);
+  grpc_channel *channel = grpc_channel_create(exec_ctx, target, new_args,
+                                              GRPC_CLIENT_CHANNEL, NULL);
+  grpc_channel_args_destroy(exec_ctx, new_args);
   return channel;
 }
 
@@ -110,6 +82,9 @@
      client_channel_factory_create_subchannel,
      client_channel_factory_create_channel};
 
+static grpc_client_channel_factory client_channel_factory = {
+    &client_channel_factory_vtable};
+
 /* Create a secure client channel:
    Asynchronously: - resolve target
                    - connect to it (trying alternatives as presented)
@@ -136,36 +111,32 @@
   grpc_channel_security_connector *security_connector;
   grpc_channel_args *new_args_from_connector;
   if (grpc_channel_credentials_create_security_connector(
-          creds, target, args, &security_connector, &new_args_from_connector) !=
-      GRPC_SECURITY_OK) {
+          &exec_ctx, creds, target, args, &security_connector,
+          &new_args_from_connector) != GRPC_SECURITY_OK) {
     grpc_exec_ctx_finish(&exec_ctx);
     return grpc_lame_client_channel_create(
         target, GRPC_STATUS_INTERNAL, "Failed to create security connector.");
   }
-  grpc_arg connector_arg =
-      grpc_security_connector_to_arg(&security_connector->base);
+  // Add channel args containing the client channel factory and security
+  // connector.
+  grpc_arg args_to_add[2];
+  args_to_add[0] =
+      grpc_client_channel_factory_create_channel_arg(&client_channel_factory);
+  args_to_add[1] = grpc_security_connector_to_arg(&security_connector->base);
   grpc_channel_args *new_args = grpc_channel_args_copy_and_add(
       new_args_from_connector != NULL ? new_args_from_connector : args,
-      &connector_arg, 1);
+      args_to_add, GPR_ARRAY_SIZE(args_to_add));
   if (new_args_from_connector != NULL) {
-    grpc_channel_args_destroy(new_args_from_connector);
+    grpc_channel_args_destroy(&exec_ctx, new_args_from_connector);
   }
-  // Create client channel factory.
-  client_channel_factory *f = gpr_malloc(sizeof(*f));
-  memset(f, 0, sizeof(*f));
-  f->base.vtable = &client_channel_factory_vtable;
-  gpr_ref_init(&f->refs, 1);
-  GRPC_SECURITY_CONNECTOR_REF(&security_connector->base,
-                              "grpc_secure_channel_create");
-  f->security_connector = security_connector;
   // Create channel.
   grpc_channel *channel = client_channel_factory_create_channel(
-      &exec_ctx, &f->base, target, GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args);
+      &exec_ctx, &client_channel_factory, target,
+      GRPC_CLIENT_CHANNEL_TYPE_REGULAR, new_args);
   // Clean up.
-  GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
+  GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &security_connector->base,
                                 "secure_client_channel_factory_create_channel");
-  grpc_channel_args_destroy(new_args);
-  grpc_client_channel_factory_unref(&exec_ctx, &f->base);
+  grpc_channel_args_destroy(&exec_ctx, new_args);
   grpc_exec_ctx_finish(&exec_ctx);
   return channel; /* may be NULL */
 }
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.c b/src/core/ext/transport/chttp2/server/chttp2_server.c
index f085771..574d1a7 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.c
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.c
@@ -46,31 +46,15 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
-void grpc_chttp2_server_handshaker_factory_add_handshakers(
-    grpc_exec_ctx *exec_ctx,
-    grpc_chttp2_server_handshaker_factory *handshaker_factory,
-    grpc_handshake_manager *handshake_mgr) {
-  if (handshaker_factory != NULL) {
-    handshaker_factory->vtable->add_handshakers(exec_ctx, handshaker_factory,
-                                                handshake_mgr);
-  }
-}
-
-void grpc_chttp2_server_handshaker_factory_destroy(
-    grpc_exec_ctx *exec_ctx,
-    grpc_chttp2_server_handshaker_factory *handshaker_factory) {
-  if (handshaker_factory != NULL) {
-    handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory);
-  }
-}
-
 typedef struct pending_handshake_manager_node {
   grpc_handshake_manager *handshake_mgr;
   struct pending_handshake_manager_node *next;
@@ -80,7 +64,6 @@
   grpc_server *server;
   grpc_tcp_server *tcp_server;
   grpc_channel_args *args;
-  grpc_chttp2_server_handshaker_factory *handshaker_factory;
   gpr_mu mu;
   bool shutdown;
   grpc_closure tcp_server_shutdown_complete;
@@ -148,8 +131,8 @@
       // point this can be removed.
       grpc_endpoint_shutdown(exec_ctx, args->endpoint);
       grpc_endpoint_destroy(exec_ctx, args->endpoint);
-      grpc_channel_args_destroy(args->args);
-      grpc_slice_buffer_destroy(args->read_buffer);
+      grpc_channel_args_destroy(exec_ctx, args->args);
+      grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer);
       gpr_free(args->read_buffer);
     }
   } else {
@@ -164,7 +147,7 @@
           connection_state->accepting_pollset, args->args);
       grpc_chttp2_transport_start_reading(exec_ctx, transport,
                                           args->read_buffer);
-      grpc_channel_args_destroy(args->args);
+      grpc_channel_args_destroy(exec_ctx, args->args);
     }
   }
   pending_handshake_manager_remove_locked(connection_state->server_state,
@@ -197,8 +180,8 @@
   connection_state->accepting_pollset = accepting_pollset;
   connection_state->acceptor = acceptor;
   connection_state->handshake_mgr = handshake_mgr;
-  grpc_chttp2_server_handshaker_factory_add_handshakers(
-      exec_ctx, state->handshaker_factory, connection_state->handshake_mgr);
+  grpc_handshakers_add(exec_ctx, HANDSHAKER_SERVER, state->args,
+                       connection_state->handshake_mgr);
   // TODO(roth): We should really get this timeout value from channel
   // args instead of hard-coding it.
   const gpr_timespec deadline = gpr_time_add(
@@ -232,13 +215,11 @@
   // Flush queued work before destroying handshaker factory, since that
   // may do a synchronous unref.
   grpc_exec_ctx_flush(exec_ctx);
-  grpc_chttp2_server_handshaker_factory_destroy(exec_ctx,
-                                                state->handshaker_factory);
   if (destroy_done != NULL) {
     destroy_done->cb(exec_ctx, destroy_done->cb_arg, GRPC_ERROR_REF(error));
     grpc_exec_ctx_flush(exec_ctx);
   }
-  grpc_channel_args_destroy(state->args);
+  grpc_channel_args_destroy(exec_ctx, state->args);
   gpr_mu_destroy(&state->mu);
   gpr_free(state);
 }
@@ -258,10 +239,10 @@
   grpc_tcp_server_unref(exec_ctx, tcp_server);
 }
 
-grpc_error *grpc_chttp2_server_add_port(
-    grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr,
-    grpc_channel_args *args,
-    grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num) {
+grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx,
+                                        grpc_server *server, const char *addr,
+                                        grpc_channel_args *args,
+                                        int *port_num) {
   grpc_resolved_addresses *resolved = NULL;
   grpc_tcp_server *tcp_server = NULL;
   size_t i;
@@ -281,7 +262,8 @@
   state = gpr_malloc(sizeof(*state));
   memset(state, 0, sizeof(*state));
   grpc_closure_init(&state->tcp_server_shutdown_complete,
-                    tcp_server_shutdown_complete, state);
+                    tcp_server_shutdown_complete, state,
+                    grpc_schedule_on_exec_ctx);
   err = grpc_tcp_server_create(exec_ctx, &state->tcp_server_shutdown_complete,
                                args, &tcp_server);
   if (err != GRPC_ERROR_NONE) {
@@ -291,7 +273,6 @@
   state->server = server;
   state->tcp_server = tcp_server;
   state->args = args;
-  state->handshaker_factory = handshaker_factory;
   state->shutdown = true;
   gpr_mu_init(&state->mu);
 
@@ -345,8 +326,7 @@
   if (tcp_server) {
     grpc_tcp_server_unref(exec_ctx, tcp_server);
   } else {
-    grpc_channel_args_destroy(args);
-    grpc_chttp2_server_handshaker_factory_destroy(exec_ctx, handshaker_factory);
+    grpc_channel_args_destroy(exec_ctx, args);
     gpr_free(state);
   }
   *port_num = 0;
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h
index aa364b5..2581eba 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.h
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.h
@@ -36,43 +36,12 @@
 
 #include <grpc/impl/codegen/grpc_types.h>
 
-#include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-/// A server handshaker factory is used to create handshakers for server
-/// connections.
-typedef struct grpc_chttp2_server_handshaker_factory
-    grpc_chttp2_server_handshaker_factory;
-
-typedef struct {
-  void (*add_handshakers)(
-      grpc_exec_ctx *exec_ctx,
-      grpc_chttp2_server_handshaker_factory *handshaker_factory,
-      grpc_handshake_manager *handshake_mgr);
-  void (*destroy)(grpc_exec_ctx *exec_ctx,
-                  grpc_chttp2_server_handshaker_factory *handshaker_factory);
-} grpc_chttp2_server_handshaker_factory_vtable;
-
-struct grpc_chttp2_server_handshaker_factory {
-  const grpc_chttp2_server_handshaker_factory_vtable *vtable;
-};
-
-void grpc_chttp2_server_handshaker_factory_add_handshakers(
-    grpc_exec_ctx *exec_ctx,
-    grpc_chttp2_server_handshaker_factory *handshaker_factory,
-    grpc_handshake_manager *handshake_mgr);
-
-void grpc_chttp2_server_handshaker_factory_destroy(
-    grpc_exec_ctx *exec_ctx,
-    grpc_chttp2_server_handshaker_factory *handshaker_factory);
-
 /// Adds a port to \a server.  Sets \a port_num to the port number.
-/// If \a handshaker_factory is not NULL, it will be used to create
-/// handshakers for the port.
-/// Takes ownership of \a args and \a handshaker_factory.
-grpc_error *grpc_chttp2_server_add_port(
-    grpc_exec_ctx *exec_ctx, grpc_server *server, const char *addr,
-    grpc_channel_args *args,
-    grpc_chttp2_server_handshaker_factory *handshaker_factory, int *port_num);
+/// Takes ownership of \a args.
+grpc_error *grpc_chttp2_server_add_port(grpc_exec_ctx *exec_ctx,
+                                        grpc_server *server, const char *addr,
+                                        grpc_channel_args *args, int *port_num);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H */
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
index 7e286d4..bf5026b 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -47,8 +47,7 @@
                  (server, addr));
   grpc_error *err = grpc_chttp2_server_add_port(
       &exec_ctx, server, addr,
-      grpc_channel_args_copy(grpc_server_get_channel_args(server)),
-      NULL /* handshaker_factory */, &port_num);
+      grpc_channel_args_copy(grpc_server_get_channel_args(server)), &port_num);
   if (err != GRPC_ERROR_NONE) {
     const char *msg = grpc_error_string(err);
     gpr_log(GPR_ERROR, "%s", msg);
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
index aa2ecf5..f46e849 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -62,7 +62,7 @@
   grpc_endpoint *server_endpoint =
       grpc_tcp_create(grpc_fd_create(fd, name), resource_quota,
                       GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
 
   gpr_free(name);
 
diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
index a33a7a3..395c79a 100644
--- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c
@@ -49,34 +49,6 @@
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
-typedef struct {
-  grpc_chttp2_server_handshaker_factory base;
-  grpc_server_security_connector *security_connector;
-} server_security_handshaker_factory;
-
-static void server_security_handshaker_factory_add_handshakers(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf,
-    grpc_handshake_manager *handshake_mgr) {
-  server_security_handshaker_factory *handshaker_factory =
-      (server_security_handshaker_factory *)hf;
-  grpc_server_security_connector_add_handshakers(
-      exec_ctx, handshaker_factory->security_connector, handshake_mgr);
-}
-
-static void server_security_handshaker_factory_destroy(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_server_handshaker_factory *hf) {
-  server_security_handshaker_factory *handshaker_factory =
-      (server_security_handshaker_factory *)hf;
-  GRPC_SECURITY_CONNECTOR_UNREF(&handshaker_factory->security_connector->base,
-                                "server");
-  gpr_free(hf);
-}
-
-static const grpc_chttp2_server_handshaker_factory_vtable
-    server_security_handshaker_factory_vtable = {
-        server_security_handshaker_factory_add_handshakers,
-        server_security_handshaker_factory_destroy};
-
 int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
                                       grpc_server_credentials *creds) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -94,7 +66,7 @@
     goto done;
   }
   grpc_security_status status =
-      grpc_server_credentials_create_security_connector(creds, &sc);
+      grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc);
   if (status != GRPC_SECURITY_OK) {
     char *msg;
     gpr_asprintf(&msg,
@@ -105,20 +77,19 @@
     gpr_free(msg);
     goto done;
   }
-  // Create handshaker factory.
-  server_security_handshaker_factory *handshaker_factory =
-      gpr_malloc(sizeof(*handshaker_factory));
-  memset(handshaker_factory, 0, sizeof(*handshaker_factory));
-  handshaker_factory->base.vtable = &server_security_handshaker_factory_vtable;
-  handshaker_factory->security_connector = sc;
   // Create channel args.
-  grpc_arg channel_arg = grpc_server_credentials_to_arg(creds);
-  grpc_channel_args *args = grpc_channel_args_copy_and_add(
-      grpc_server_get_channel_args(server), &channel_arg, 1);
+  grpc_arg args_to_add[2];
+  args_to_add[0] = grpc_server_credentials_to_arg(creds);
+  args_to_add[1] = grpc_security_connector_to_arg(&sc->base);
+  grpc_channel_args *args =
+      grpc_channel_args_copy_and_add(grpc_server_get_channel_args(server),
+                                     args_to_add, GPR_ARRAY_SIZE(args_to_add));
   // Add server port.
-  err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args,
-                                    &handshaker_factory->base, &port_num);
+  err = grpc_chttp2_server_add_port(&exec_ctx, server, addr, args, &port_num);
 done:
+  if (sc != NULL) {
+    GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &sc->base, "server");
+  }
   grpc_exec_ctx_finish(&exec_ctx);
   if (err != GRPC_ERROR_NONE) {
     const char *msg = grpc_error_string(err);
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.c b/src/core/ext/transport/chttp2/transport/bin_decoder.c
index 3eef80b..8db36e4 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.c
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -34,6 +34,7 @@
 #include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
@@ -143,7 +144,8 @@
   return true;
 }
 
-grpc_slice grpc_chttp2_base64_decode(grpc_slice input) {
+grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx,
+                                     grpc_slice input) {
   size_t input_length = GRPC_SLICE_LENGTH(input);
   size_t output_length = input_length / 4 * 3;
   struct grpc_base64_decode_context ctx;
@@ -179,7 +181,7 @@
     char *s = grpc_dump_slice(input, GPR_DUMP_ASCII);
     gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
     gpr_free(s);
-    grpc_slice_unref(output);
+    grpc_slice_unref_internal(exec_ctx, output);
     return gpr_empty_slice();
   }
   GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
@@ -187,7 +189,8 @@
   return output;
 }
 
-grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input,
+grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx,
+                                                 grpc_slice input,
                                                  size_t output_length) {
   size_t input_length = GRPC_SLICE_LENGTH(input);
   grpc_slice output = grpc_slice_malloc(output_length);
@@ -200,7 +203,7 @@
             "grpc_chttp2_base64_decode_with_length has a length of %d, which "
             "has a tail of 1 byte.\n",
             (int)input_length);
-    grpc_slice_unref(output);
+    grpc_slice_unref_internal(exec_ctx, output);
     return gpr_empty_slice();
   }
 
@@ -210,7 +213,7 @@
             "than the max possible output length %d.\n",
             (int)output_length,
             (int)(input_length / 4 * 3 + tail_xtra[input_length % 4]));
-    grpc_slice_unref(output);
+    grpc_slice_unref_internal(exec_ctx, output);
     return gpr_empty_slice();
   }
 
@@ -224,7 +227,7 @@
     char *s = grpc_dump_slice(input, GPR_DUMP_ASCII);
     gpr_log(GPR_ERROR, "Base64 decoding failed, input string:\n%s\n", s);
     gpr_free(s);
-    grpc_slice_unref(output);
+    grpc_slice_unref_internal(exec_ctx, output);
     return gpr_empty_slice();
   }
   GPR_ASSERT(ctx.output_cur == GRPC_SLICE_END_PTR(output));
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
index 83a90be..48ffb2a 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -55,12 +55,13 @@
 
 /* base64 decode a slice with pad chars. Returns a new slice, does not take
    ownership of the input. Returns an empty slice if decoding is failed. */
-grpc_slice grpc_chttp2_base64_decode(grpc_slice input);
+grpc_slice grpc_chttp2_base64_decode(grpc_exec_ctx *exec_ctx, grpc_slice input);
 
 /* base64 decode a slice without pad chars, data length is needed. Returns a new
    slice, does not take ownership of the input. Returns an empty slice if
    decoding is failed. */
-grpc_slice grpc_chttp2_base64_decode_with_length(grpc_slice input,
+grpc_slice grpc_chttp2_base64_decode_with_length(grpc_exec_ctx *exec_ctx,
+                                                 grpc_slice input,
                                                  size_t output_length);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.h b/src/core/ext/transport/chttp2/transport/bin_encoder.h
index 9e143b4..477559d 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.h
@@ -47,7 +47,7 @@
 /* equivalent to:
    grpc_slice x = grpc_chttp2_base64_encode(input);
    grpc_slice y = grpc_chttp2_huffman_compress(x);
-   grpc_slice_unref(x);
+   grpc_slice_unref_internal(exec_ctx, x);
    return y; */
 grpc_slice grpc_chttp2_base64_encode_and_huffman_compress_impl(
     grpc_slice input);
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 6bc0548..8fe12a2 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -47,10 +47,12 @@
 #include "src/core/ext/transport/chttp2/transport/http2_errors.h"
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/ext/transport/chttp2/transport/status_conversion.h"
+#include "src/core/ext/transport/chttp2/transport/varint.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/http/parser.h"
 #include "src/core/lib/iomgr/workqueue.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/static_metadata.h"
@@ -73,20 +75,14 @@
 static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *t,
                                       grpc_error *error);
 static void write_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
-static void write_action_end(grpc_exec_ctx *exec_ctx, void *t,
-                             grpc_error *error);
 static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *t,
                                     grpc_error *error);
 
-static void read_action_begin(grpc_exec_ctx *exec_ctx, void *t,
-                              grpc_error *error);
 static void read_action_locked(grpc_exec_ctx *exec_ctx, void *t,
                                grpc_error *error);
 
 static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs,
                                   grpc_error *error);
-static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs,
-                           grpc_error *error);
 /** Set a transport level setting, and push it to our peer */
 static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                          grpc_chttp2_setting_id id, uint32_t value);
@@ -112,12 +108,8 @@
                                                 void *byte_stream,
                                                 grpc_error *error_ignored);
 
-static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
-                             grpc_error *error);
 static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t,
                                     grpc_error *error);
-static void destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *t,
-                                  grpc_error *error);
 static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *t,
                                          grpc_error *error);
 
@@ -141,13 +133,13 @@
 
   grpc_endpoint_destroy(exec_ctx, t->ep);
 
-  grpc_slice_buffer_destroy(&t->qbuf);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &t->qbuf);
 
-  grpc_slice_buffer_destroy(&t->outbuf);
-  grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &t->outbuf);
+  grpc_chttp2_hpack_compressor_destroy(exec_ctx, &t->hpack_compressor);
 
-  grpc_slice_buffer_destroy(&t->read_buffer);
-  grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &t->read_buffer);
+  grpc_chttp2_hpack_parser_destroy(exec_ctx, &t->hpack_parser);
   grpc_chttp2_goaway_parser_destroy(&t->goaway_parser);
 
   for (i = 0; i < STREAM_LIST_COUNT; i++) {
@@ -166,8 +158,8 @@
      and maybe they hold resources that need to be freed */
   while (t->pings.next != &t->pings) {
     grpc_chttp2_outstanding_ping *ping = t->pings.next;
-    grpc_exec_ctx_sched(exec_ctx, ping->on_recv,
-                        GRPC_ERROR_CREATE("Transport closed"), NULL);
+    grpc_closure_sched(exec_ctx, ping->on_recv,
+                       GRPC_ERROR_CREATE("Transport closed"));
     ping->next->prev = ping->prev;
     ping->prev->next = ping->next;
     gpr_free(ping);
@@ -246,21 +238,18 @@
   grpc_slice_buffer_init(&t->outbuf);
   grpc_chttp2_hpack_compressor_init(&t->hpack_compressor);
 
-  grpc_closure_init(&t->write_action_begin_locked, write_action_begin_locked,
-                    t);
-  grpc_closure_init(&t->write_action, write_action, t);
-  grpc_closure_init(&t->write_action_end, write_action_end, t);
-  grpc_closure_init(&t->write_action_end_locked, write_action_end_locked, t);
-  grpc_closure_init(&t->read_action_begin, read_action_begin, t);
-  grpc_closure_init(&t->read_action_locked, read_action_locked, t);
-  grpc_closure_init(&t->benign_reclaimer, benign_reclaimer, t);
-  grpc_closure_init(&t->destructive_reclaimer, destructive_reclaimer, t);
-  grpc_closure_init(&t->benign_reclaimer_locked, benign_reclaimer_locked, t);
+  grpc_closure_init(&t->write_action, write_action, t,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&t->read_action_locked, read_action_locked, t,
+                    grpc_combiner_scheduler(t->combiner, false));
+  grpc_closure_init(&t->benign_reclaimer_locked, benign_reclaimer_locked, t,
+                    grpc_combiner_scheduler(t->combiner, false));
   grpc_closure_init(&t->destructive_reclaimer_locked,
-                    destructive_reclaimer_locked, t);
+                    destructive_reclaimer_locked, t,
+                    grpc_combiner_scheduler(t->combiner, false));
 
   grpc_chttp2_goaway_parser_init(&t->goaway_parser);
-  grpc_chttp2_hpack_parser_init(&t->hpack_parser);
+  grpc_chttp2_hpack_parser_init(exec_ctx, &t->hpack_parser);
 
   grpc_slice_buffer_init(&t->read_buffer);
 
@@ -395,9 +384,10 @@
 
 static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  grpc_combiner_execute(exec_ctx, t->combiner,
-                        grpc_closure_create(destroy_transport_locked, t),
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(exec_ctx, grpc_closure_create(
+                                   destroy_transport_locked, t,
+                                   grpc_combiner_scheduler(t->combiner, false)),
+                     GRPC_ERROR_NONE);
 }
 
 static void close_transport_locked(grpc_exec_ctx *exec_ctx,
@@ -471,8 +461,8 @@
   grpc_chttp2_data_parser_init(&s->data_parser);
   grpc_slice_buffer_init(&s->flow_controlled_buffer);
   s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
-  grpc_closure_init(&s->complete_fetch, complete_fetch, s);
-  grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s);
+  grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s,
+                    grpc_schedule_on_exec_ctx);
 
   GRPC_CHTTP2_REF_TRANSPORT(t, "stream");
 
@@ -527,9 +517,11 @@
   GPR_ASSERT(s->recv_message_ready == NULL);
   GPR_ASSERT(s->recv_trailing_metadata_finished == NULL);
   grpc_chttp2_data_parser_destroy(exec_ctx, &s->data_parser);
-  grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]);
-  grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]);
-  grpc_slice_buffer_destroy(&s->flow_controlled_buffer);
+  grpc_chttp2_incoming_metadata_buffer_destroy(exec_ctx,
+                                               &s->metadata_buffer[0]);
+  grpc_chttp2_incoming_metadata_buffer_destroy(exec_ctx,
+                                               &s->metadata_buffer[1]);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &s->flow_controlled_buffer);
   GRPC_ERROR_UNREF(s->read_closed_error);
   GRPC_ERROR_UNREF(s->write_closed_error);
 
@@ -547,9 +539,10 @@
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
   s->destroy_stream_arg = and_free_memory;
-  grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s);
-  grpc_combiner_execute(exec_ctx, t->combiner, &s->destroy_stream,
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(
+      exec_ctx, grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s,
+                                  grpc_combiner_scheduler(t->combiner, false)),
+      GRPC_ERROR_NONE);
   GPR_TIMER_END("destroy_stream", 0);
 }
 
@@ -600,7 +593,7 @@
                                  write_state_name(st), reason));
   t->write_state = st;
   if (st == GRPC_CHTTP2_WRITE_STATE_IDLE) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &t->run_after_write, NULL);
+    grpc_closure_list_sched(exec_ctx, &t->run_after_write);
     if (t->close_transport_on_writes_finished != NULL) {
       grpc_error *err = t->close_transport_on_writes_finished;
       t->close_transport_on_writes_finished = NULL;
@@ -618,9 +611,12 @@
     case GRPC_CHTTP2_WRITE_STATE_IDLE:
       set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING, reason);
       GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
-      grpc_combiner_execute_finally(exec_ctx, t->combiner,
-                                    &t->write_action_begin_locked,
-                                    GRPC_ERROR_NONE, covered_by_poller);
+      grpc_closure_sched(
+          exec_ctx,
+          grpc_closure_init(
+              &t->write_action_begin_locked, write_action_begin_locked, t,
+              grpc_combiner_finally_scheduler(t->combiner, covered_by_poller)),
+          GRPC_ERROR_NONE);
       break;
     case GRPC_CHTTP2_WRITE_STATE_WRITING:
       set_write_state(
@@ -662,7 +658,7 @@
   if (!t->closed && grpc_chttp2_begin_write(exec_ctx, t)) {
     set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING,
                     "begin writing");
-    grpc_exec_ctx_sched(exec_ctx, &t->write_action, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, &t->write_action, GRPC_ERROR_NONE);
   } else {
     set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_IDLE,
                     "begin writing nothing");
@@ -674,19 +670,13 @@
 static void write_action(grpc_exec_ctx *exec_ctx, void *gt, grpc_error *error) {
   grpc_chttp2_transport *t = gt;
   GPR_TIMER_BEGIN("write_action", 0);
-  grpc_endpoint_write(exec_ctx, t->ep, &t->outbuf, &t->write_action_end);
+  grpc_endpoint_write(
+      exec_ctx, t->ep, &t->outbuf,
+      grpc_closure_init(&t->write_action_end_locked, write_action_end_locked, t,
+                        grpc_combiner_scheduler(t->combiner, false)));
   GPR_TIMER_END("write_action", 0);
 }
 
-static void write_action_end(grpc_exec_ctx *exec_ctx, void *gt,
-                             grpc_error *error) {
-  grpc_chttp2_transport *t = gt;
-  GPR_TIMER_BEGIN("write_action_end", 0);
-  grpc_combiner_execute(exec_ctx, t->combiner, &t->write_action_end_locked,
-                        GRPC_ERROR_REF(error), false);
-  GPR_TIMER_END("write_action_end", 0);
-}
-
 static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
                                     grpc_error *error) {
   GPR_TIMER_BEGIN("terminate_writing_with_lock", 0);
@@ -716,18 +706,24 @@
       set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING,
                       "continue writing [!covered]");
       GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
-      grpc_combiner_execute_finally(exec_ctx, t->combiner,
-                                    &t->write_action_begin_locked,
-                                    GRPC_ERROR_NONE, false);
+      grpc_closure_run(
+          exec_ctx,
+          grpc_closure_init(
+              &t->write_action_begin_locked, write_action_begin_locked, t,
+              grpc_combiner_finally_scheduler(t->combiner, false)),
+          GRPC_ERROR_NONE);
       break;
     case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER:
       GPR_TIMER_MARK("state=writing_stale_with_poller", 0);
       set_write_state(exec_ctx, t, GRPC_CHTTP2_WRITE_STATE_WRITING,
                       "continue writing [covered]");
       GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
-      grpc_combiner_execute_finally(exec_ctx, t->combiner,
-                                    &t->write_action_begin_locked,
-                                    GRPC_ERROR_NONE, true);
+      grpc_closure_run(
+          exec_ctx,
+          grpc_closure_init(&t->write_action_begin_locked,
+                            write_action_begin_locked, t,
+                            grpc_combiner_finally_scheduler(t->combiner, true)),
+          GRPC_ERROR_NONE);
       break;
   }
 
@@ -760,7 +756,7 @@
   char *msg = grpc_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
   GRPC_CHTTP2_IF_TRACING(
       gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
-  grpc_slice_unref(goaway_text);
+  grpc_slice_unref_internal(exec_ctx, goaway_text);
   t->seen_goaway = 1;
   /* lie: use transient failure from the transport to indicate goaway has been
    * received */
@@ -965,15 +961,6 @@
   }
 }
 
-static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs,
-                           grpc_error *error) {
-  grpc_chttp2_stream *s = gs;
-  grpc_chttp2_transport *t = s->t;
-  grpc_combiner_execute(exec_ctx, t->combiner, &s->complete_fetch_locked,
-                        GRPC_ERROR_REF(error),
-                        s->complete_fetch_covered_by_poller);
-}
-
 static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
 
 static void log_metadata(const grpc_metadata_batch *md_batch, uint32_t id,
@@ -1009,7 +996,8 @@
 
   grpc_closure *on_complete = op->on_complete;
   if (on_complete == NULL) {
-    on_complete = grpc_closure_create(do_nothing, NULL);
+    on_complete =
+        grpc_closure_create(do_nothing, NULL, grpc_schedule_on_exec_ctx);
   }
 
   /* use final_data as a barrier until enqueue time; the inital counter is
@@ -1212,13 +1200,15 @@
     gpr_free(str);
   }
 
-  grpc_closure_init(&op->transport_private.closure, perform_stream_op_locked,
-                    op);
   op->transport_private.args[0] = gt;
   op->transport_private.args[1] = gs;
   GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op");
-  grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure,
-                        GRPC_ERROR_NONE, op->covered_by_poller);
+  grpc_closure_sched(
+      exec_ctx,
+      grpc_closure_init(
+          &op->transport_private.closure, perform_stream_op_locked, op,
+          grpc_combiner_scheduler(t->combiner, op->covered_by_poller)),
+      GRPC_ERROR_NONE);
   GPR_TIMER_END("perform_stream_op", 0);
 }
 
@@ -1247,7 +1237,7 @@
   grpc_chttp2_outstanding_ping *ping;
   for (ping = t->pings.next; ping != &t->pings; ping = ping->next) {
     if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
-      grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL);
+      grpc_closure_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE);
       ping->next->prev = ping->prev;
       ping->prev->next = ping->next;
       gpr_free(ping);
@@ -1285,7 +1275,7 @@
   if (op->send_goaway) {
     send_goaway(exec_ctx, t,
                 grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
-                grpc_slice_ref(*op->goaway_message));
+                grpc_slice_ref_internal(*op->goaway_message));
   }
 
   if (op->set_accept_stream) {
@@ -1321,11 +1311,12 @@
   char *msg = grpc_transport_op_string(op);
   gpr_free(msg);
   op->transport_private.args[0] = gt;
-  grpc_closure_init(&op->transport_private.closure, perform_transport_op_locked,
-                    op);
   GRPC_CHTTP2_REF_TRANSPORT(t, "transport_op");
-  grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure,
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(
+      exec_ctx, grpc_closure_init(&op->transport_private.closure,
+                                  perform_transport_op_locked, op,
+                                  grpc_combiner_scheduler(t->combiner, false)),
+      GRPC_ERROR_NONE);
 }
 
 /*******************************************************************************
@@ -1515,21 +1506,22 @@
     char status_string[GPR_LTOA_MIN_BUFSIZE];
     gpr_ltoa(status, status_string);
     grpc_chttp2_incoming_metadata_buffer_add(
-        &s->metadata_buffer[1],
-        grpc_mdelem_from_metadata_strings(
-            GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
+        &s->metadata_buffer[1], grpc_mdelem_from_metadata_strings(
+                                    exec_ctx, GRPC_MDSTR_GRPC_STATUS,
+                                    grpc_mdstr_from_string(status_string)));
     if (slice) {
       grpc_chttp2_incoming_metadata_buffer_add(
           &s->metadata_buffer[1],
           grpc_mdelem_from_metadata_strings(
-              GRPC_MDSTR_GRPC_MESSAGE,
-              grpc_mdstr_from_slice(grpc_slice_ref(*slice))));
+              exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+              grpc_mdstr_from_slice(exec_ctx,
+                                    grpc_slice_ref_internal(*slice))));
     }
     s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
     grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
   }
   if (slice) {
-    grpc_slice_unref(*slice);
+    grpc_slice_unref_internal(exec_ctx, *slice);
   }
 }
 
@@ -1685,8 +1677,9 @@
 
     if (optional_message != NULL) {
       size_t msg_len = strlen(optional_message);
-      GPR_ASSERT(msg_len < 127);
-      message_pfx = grpc_slice_malloc(15);
+      GPR_ASSERT(msg_len <= UINT32_MAX);
+      uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0);
+      message_pfx = grpc_slice_malloc(14 + msg_len_len);
       p = GRPC_SLICE_START_PTR(message_pfx);
       *p++ = 0x40;
       *p++ = 12; /* len(grpc-message) */
@@ -1702,7 +1695,9 @@
       *p++ = 'a';
       *p++ = 'g';
       *p++ = 'e';
-      *p++ = (uint8_t)msg_len;
+      GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p,
+                               (uint32_t)msg_len_len);
+      p += msg_len_len;
       GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
       len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
       len += (uint32_t)msg_len;
@@ -1801,19 +1796,6 @@
  * INPUT PROCESSING - PARSING
  */
 
-static void read_action_begin(grpc_exec_ctx *exec_ctx, void *tp,
-                              grpc_error *error) {
-  /* Control flow:
-     reading_action_locked ->
-       (parse_unlocked -> post_parse_locked)? ->
-       post_reading_action_locked */
-  GPR_TIMER_BEGIN("reading_action", 0);
-  grpc_chttp2_transport *t = tp;
-  grpc_combiner_execute(exec_ctx, t->combiner, &t->read_action_locked,
-                        GRPC_ERROR_REF(error), false);
-  GPR_TIMER_END("reading_action", 0);
-}
-
 static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
                                     grpc_chttp2_transport *t) {
   grpc_http_parser parser;
@@ -1910,10 +1892,11 @@
     keep_reading = true;
     GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading");
   }
-  grpc_slice_buffer_reset_and_unref(&t->read_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &t->read_buffer);
 
   if (keep_reading) {
-    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_begin);
+    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer,
+                       &t->read_action_locked);
     GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
   } else {
     GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action");
@@ -1964,7 +1947,7 @@
                                        grpc_chttp2_incoming_byte_stream *bs) {
   if (gpr_unref(&bs->refs)) {
     GRPC_ERROR_UNREF(bs->error);
-    grpc_slice_buffer_destroy(&bs->slices);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &bs->slices);
     gpr_mu_destroy(&bs->slice_mu);
     gpr_free(bs);
   }
@@ -2050,10 +2033,12 @@
   bs->next_action.slice = slice;
   bs->next_action.max_size_hint = max_size_hint;
   bs->next_action.on_complete = on_complete;
-  grpc_closure_init(&bs->next_action.closure, incoming_byte_stream_next_locked,
-                    bs);
-  grpc_combiner_execute(exec_ctx, bs->transport->combiner,
-                        &bs->next_action.closure, GRPC_ERROR_NONE, false);
+  grpc_closure_sched(
+      exec_ctx,
+      grpc_closure_init(
+          &bs->next_action.closure, incoming_byte_stream_next_locked, bs,
+          grpc_combiner_scheduler(bs->transport->combiner, false)),
+      GRPC_ERROR_NONE);
   GPR_TIMER_END("incoming_byte_stream_next", 0);
   return 0;
 }
@@ -2075,10 +2060,12 @@
   GPR_TIMER_BEGIN("incoming_byte_stream_destroy", 0);
   grpc_chttp2_incoming_byte_stream *bs =
       (grpc_chttp2_incoming_byte_stream *)byte_stream;
-  grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked,
-                    bs);
-  grpc_combiner_execute(exec_ctx, bs->transport->combiner, &bs->destroy_action,
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(
+      exec_ctx,
+      grpc_closure_init(
+          &bs->destroy_action, incoming_byte_stream_destroy_locked, bs,
+          grpc_combiner_scheduler(bs->transport->combiner, false)),
+      GRPC_ERROR_NONE);
   GPR_TIMER_END("incoming_byte_stream_destroy", 0);
 }
 
@@ -2086,7 +2073,7 @@
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
     grpc_error *error) {
   GPR_ASSERT(error != GRPC_ERROR_NONE);
-  grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL);
+  grpc_closure_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error));
   bs->on_next = NULL;
   GRPC_ERROR_UNREF(bs->error);
   bs->error = error;
@@ -2103,7 +2090,7 @@
     bs->remaining_bytes -= (uint32_t)GRPC_SLICE_LENGTH(slice);
     if (bs->on_next != NULL) {
       *bs->next = slice;
-      grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
+      grpc_closure_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE);
       bs->on_next = NULL;
     } else {
       grpc_slice_buffer_add(&bs->slices, slice);
@@ -2171,7 +2158,7 @@
     GRPC_CHTTP2_REF_TRANSPORT(t, "benign_reclaimer");
     grpc_resource_user_post_reclaimer(exec_ctx,
                                       grpc_endpoint_get_resource_user(t->ep),
-                                      false, &t->benign_reclaimer);
+                                      false, &t->benign_reclaimer_locked);
   }
 }
 
@@ -2182,24 +2169,10 @@
     GRPC_CHTTP2_REF_TRANSPORT(t, "destructive_reclaimer");
     grpc_resource_user_post_reclaimer(exec_ctx,
                                       grpc_endpoint_get_resource_user(t->ep),
-                                      true, &t->destructive_reclaimer);
+                                      true, &t->destructive_reclaimer_locked);
   }
 }
 
-static void benign_reclaimer(grpc_exec_ctx *exec_ctx, void *arg,
-                             grpc_error *error) {
-  grpc_chttp2_transport *t = arg;
-  grpc_combiner_execute(exec_ctx, t->combiner, &t->benign_reclaimer_locked,
-                        GRPC_ERROR_REF(error), false);
-}
-
-static void destructive_reclaimer(grpc_exec_ctx *exec_ctx, void *arg,
-                                  grpc_error *error) {
-  grpc_chttp2_transport *t = arg;
-  grpc_combiner_execute(exec_ctx, t->combiner, &t->destructive_reclaimer_locked,
-                        GRPC_ERROR_REF(error), false);
-}
-
 static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
                                     grpc_error *error) {
   grpc_chttp2_transport *t = arg;
@@ -2380,5 +2353,5 @@
     grpc_slice_buffer_move_into(read_buffer, &t->read_buffer);
     gpr_free(read_buffer);
   }
-  read_action_begin(exec_ctx, t, GRPC_ERROR_NONE);
+  grpc_closure_sched(exec_ctx, &t->read_action_locked, GRPC_ERROR_NONE);
 }
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
index b4c5ed7..20043f5 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -109,7 +109,7 @@
                       (((uint32_t)p->reason_bytes[2]) << 8) |
                       (((uint32_t)p->reason_bytes[3]));
     grpc_error *error = GRPC_ERROR_NONE;
-    if (reason != GRPC_CHTTP2_NO_ERROR) {
+    if (reason != GRPC_CHTTP2_NO_ERROR || s->header_frames_received < 2) {
       error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"),
                                  GRPC_ERROR_INT_HTTP2_ERROR, (intptr_t)reason);
       grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index eb68fe3..49a8326 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -48,6 +48,7 @@
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
 #include "src/core/ext/transport/chttp2/transport/hpack_table.h"
 #include "src/core/ext/transport/chttp2/transport/varint.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/timeout_encoding.h"
@@ -183,7 +184,8 @@
 }
 
 /* add an element to the decoder table */
-static void add_elem(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem) {
+static void add_elem(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
+                     grpc_mdelem *elem) {
   uint32_t key_hash = elem->key->hash;
   uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
   uint32_t new_index = c->tail_remote_index + c->table_elems + 1;
@@ -227,12 +229,12 @@
   } else if (c->indices_elems[HASH_FRAGMENT_2(elem_hash)] <
              c->indices_elems[HASH_FRAGMENT_3(elem_hash)]) {
     /* not there: replace oldest */
-    GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
+    GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_2(elem_hash)]);
     c->entries_elems[HASH_FRAGMENT_2(elem_hash)] = GRPC_MDELEM_REF(elem);
     c->indices_elems[HASH_FRAGMENT_2(elem_hash)] = new_index;
   } else {
     /* not there: replace oldest */
-    GRPC_MDELEM_UNREF(c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
+    GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[HASH_FRAGMENT_3(elem_hash)]);
     c->entries_elems[HASH_FRAGMENT_3(elem_hash)] = GRPC_MDELEM_REF(elem);
     c->indices_elems[HASH_FRAGMENT_3(elem_hash)] = new_index;
   }
@@ -251,11 +253,11 @@
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   } else if (c->indices_keys[HASH_FRAGMENT_2(key_hash)] <
              c->indices_keys[HASH_FRAGMENT_3(key_hash)]) {
-    GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
+    GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[HASH_FRAGMENT_2(key_hash)]);
     c->entries_keys[HASH_FRAGMENT_2(key_hash)] = GRPC_MDSTR_REF(elem->key);
     c->indices_keys[HASH_FRAGMENT_2(key_hash)] = new_index;
   } else {
-    GRPC_MDSTR_UNREF(c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
+    GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[HASH_FRAGMENT_3(key_hash)]);
     c->entries_keys[HASH_FRAGMENT_3(key_hash)] = GRPC_MDSTR_REF(elem->key);
     c->indices_keys[HASH_FRAGMENT_3(key_hash)] = new_index;
   }
@@ -294,7 +296,7 @@
                            add_tiny_header_data(st, len_pfx), len_pfx);
   GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, grpc_slice_ref(value_slice));
+  add_header_data(st, grpc_slice_ref_internal(value_slice));
 }
 
 static void emit_lithdr_noidx(grpc_chttp2_hpack_compressor *c,
@@ -311,7 +313,7 @@
                            add_tiny_header_data(st, len_pfx), len_pfx);
   GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, grpc_slice_ref(value_slice));
+  add_header_data(st, grpc_slice_ref_internal(value_slice));
 }
 
 static void emit_lithdr_incidx_v(grpc_chttp2_hpack_compressor *c,
@@ -327,10 +329,10 @@
   *add_tiny_header_data(st, 1) = 0x40;
   GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
                            add_tiny_header_data(st, len_key_len), len_key_len);
-  add_header_data(st, grpc_slice_ref(elem->key->slice));
+  add_header_data(st, grpc_slice_ref_internal(elem->key->slice));
   GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, grpc_slice_ref(value_slice));
+  add_header_data(st, grpc_slice_ref_internal(value_slice));
 }
 
 static void emit_lithdr_noidx_v(grpc_chttp2_hpack_compressor *c,
@@ -346,10 +348,10 @@
   *add_tiny_header_data(st, 1) = 0x00;
   GRPC_CHTTP2_WRITE_VARINT(len_key, 1, 0x00,
                            add_tiny_header_data(st, len_key_len), len_key_len);
-  add_header_data(st, grpc_slice_ref(elem->key->slice));
+  add_header_data(st, grpc_slice_ref_internal(elem->key->slice));
   GRPC_CHTTP2_WRITE_VARINT(len_val, 1, huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
-  add_header_data(st, grpc_slice_ref(value_slice));
+  add_header_data(st, grpc_slice_ref_internal(value_slice));
 }
 
 static void emit_advertise_table_size_change(grpc_chttp2_hpack_compressor *c,
@@ -366,8 +368,8 @@
 }
 
 /* encode an mdelem */
-static void hpack_enc(grpc_chttp2_hpack_compressor *c, grpc_mdelem *elem,
-                      framer_state *st) {
+static void hpack_enc(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_compressor *c,
+                      grpc_mdelem *elem, framer_state *st) {
   uint32_t key_hash = elem->key->hash;
   uint32_t elem_hash = GRPC_MDSTR_KV_HASH(key_hash, elem->value->hash);
   size_t decoder_space_usage;
@@ -417,7 +419,7 @@
     /* HIT: key (first cuckoo hash) */
     if (should_add_elem) {
       emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem);
+      add_elem(exec_ctx, c, elem);
       return;
     } else {
       emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
@@ -432,7 +434,7 @@
     /* HIT: key (first cuckoo hash) */
     if (should_add_elem) {
       emit_lithdr_incidx(c, dynidx(c, indices_key), elem, st);
-      add_elem(c, elem);
+      add_elem(exec_ctx, c, elem);
       return;
     } else {
       emit_lithdr_noidx(c, dynidx(c, indices_key), elem, st);
@@ -445,7 +447,7 @@
 
   if (should_add_elem) {
     emit_lithdr_incidx_v(c, elem, st);
-    add_elem(c, elem);
+    add_elem(exec_ctx, c, elem);
     return;
   } else {
     emit_lithdr_noidx_v(c, elem, st);
@@ -457,16 +459,17 @@
 #define STRLEN_LIT(x) (sizeof(x) - 1)
 #define TIMEOUT_KEY "grpc-timeout"
 
-static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
+static void deadline_enc(grpc_exec_ctx *exec_ctx,
+                         grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
                          framer_state *st) {
   char timeout_str[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
   grpc_mdelem *mdelem;
   grpc_http2_encode_timeout(
       gpr_time_sub(deadline, gpr_now(deadline.clock_type)), timeout_str);
   mdelem = grpc_mdelem_from_metadata_strings(
-      GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
-  hpack_enc(c, mdelem, st);
-  GRPC_MDELEM_UNREF(mdelem);
+      exec_ctx, GRPC_MDSTR_GRPC_TIMEOUT, grpc_mdstr_from_string(timeout_str));
+  hpack_enc(exec_ctx, c, mdelem, st);
+  GRPC_MDELEM_UNREF(exec_ctx, mdelem);
 }
 
 static uint32_t elems_for_bytes(uint32_t bytes) { return (bytes + 31) / 32; }
@@ -483,11 +486,12 @@
          sizeof(*c->table_elem_size) * c->cap_table_elems);
 }
 
-void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
+void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_hpack_compressor *c) {
   int i;
   for (i = 0; i < GRPC_CHTTP2_HPACKC_NUM_VALUES; i++) {
-    if (c->entries_keys[i]) GRPC_MDSTR_UNREF(c->entries_keys[i]);
-    if (c->entries_elems[i]) GRPC_MDELEM_UNREF(c->entries_elems[i]);
+    if (c->entries_keys[i]) GRPC_MDSTR_UNREF(exec_ctx, c->entries_keys[i]);
+    if (c->entries_elems[i]) GRPC_MDELEM_UNREF(exec_ctx, c->entries_elems[i]);
   }
   gpr_free(c->table_elem_size);
 }
@@ -542,7 +546,8 @@
   }
 }
 
-void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c,
+void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_compressor *c,
                                uint32_t stream_id,
                                grpc_metadata_batch *metadata, int is_eof,
                                size_t max_frame_size,
@@ -571,11 +576,11 @@
   }
   grpc_metadata_batch_assert_ok(metadata);
   for (l = metadata->list.head; l; l = l->next) {
-    hpack_enc(c, l->md, &st);
+    hpack_enc(exec_ctx, c, l->md, &st);
   }
   deadline = metadata->deadline;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) != 0) {
-    deadline_enc(c, deadline, &st);
+    deadline_enc(exec_ctx, c, deadline, &st);
   }
 
   finish_frame(&st, 1, is_eof);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index bcbd675..3a35496 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -83,13 +83,15 @@
 } grpc_chttp2_hpack_compressor;
 
 void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c);
-void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
+void grpc_chttp2_hpack_compressor_destroy(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_hpack_compressor *c);
 void grpc_chttp2_hpack_compressor_set_max_table_size(
     grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
 void grpc_chttp2_hpack_compressor_set_max_usable_size(
     grpc_chttp2_hpack_compressor *c, uint32_t max_table_size);
 
-void grpc_chttp2_encode_header(grpc_chttp2_hpack_compressor *c, uint32_t id,
+void grpc_chttp2_encode_header(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_compressor *c, uint32_t id,
                                grpc_metadata_batch *metadata, int is_eof,
                                size_t max_frame_size,
                                grpc_transport_one_way_stats *stats,
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 6a9200b..8b91cc7 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -670,11 +670,11 @@
 static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
                           grpc_mdelem *md, int add_to_table) {
   if (add_to_table) {
-    grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md);
+    grpc_error *err = grpc_chttp2_hptbl_add(exec_ctx, &p->table, md);
     if (err != GRPC_ERROR_NONE) return err;
   }
   if (p->on_header == NULL) {
-    GRPC_MDELEM_UNREF(md);
+    GRPC_MDELEM_UNREF(exec_ctx, md);
     return GRPC_ERROR_CREATE("on_header callback not set");
   }
   p->on_header(exec_ctx, p->on_header_user_data, md);
@@ -815,10 +815,10 @@
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   GPR_ASSERT(md != NULL); /* handled in string parsing */
-  grpc_error *err = on_hdr(
-      exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                     take_string(p, &p->value)),
-      1);
+  grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+                                            exec_ctx, GRPC_MDSTR_REF(md->key),
+                                            take_string(p, &p->value)),
+                           1);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -828,10 +828,10 @@
                                           grpc_chttp2_hpack_parser *p,
                                           const uint8_t *cur,
                                           const uint8_t *end) {
-  grpc_error *err = on_hdr(
-      exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                     take_string(p, &p->value)),
-      1);
+  grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+                                            exec_ctx, take_string(p, &p->key),
+                                            take_string(p, &p->value)),
+                           1);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -883,10 +883,10 @@
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   GPR_ASSERT(md != NULL); /* handled in string parsing */
-  grpc_error *err = on_hdr(
-      exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                     take_string(p, &p->value)),
-      0);
+  grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+                                            exec_ctx, GRPC_MDSTR_REF(md->key),
+                                            take_string(p, &p->value)),
+                           0);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -896,10 +896,10 @@
                                           grpc_chttp2_hpack_parser *p,
                                           const uint8_t *cur,
                                           const uint8_t *end) {
-  grpc_error *err = on_hdr(
-      exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                     take_string(p, &p->value)),
-      0);
+  grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+                                            exec_ctx, take_string(p, &p->key),
+                                            take_string(p, &p->value)),
+                           0);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -951,10 +951,10 @@
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   GPR_ASSERT(md != NULL); /* handled in string parsing */
-  grpc_error *err = on_hdr(
-      exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                     take_string(p, &p->value)),
-      0);
+  grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+                                            exec_ctx, GRPC_MDSTR_REF(md->key),
+                                            take_string(p, &p->value)),
+                           0);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -964,10 +964,10 @@
                                           grpc_chttp2_hpack_parser *p,
                                           const uint8_t *cur,
                                           const uint8_t *end) {
-  grpc_error *err = on_hdr(
-      exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                     take_string(p, &p->value)),
-      0);
+  grpc_error *err = on_hdr(exec_ctx, p, grpc_mdelem_from_metadata_strings(
+                                            exec_ctx, take_string(p, &p->key),
+                                            take_string(p, &p->value)),
+                           0);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -1020,7 +1020,7 @@
     gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
   }
   grpc_error *err =
-      grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
+      grpc_chttp2_hptbl_set_current_table_size(exec_ctx, &p->table, p->index);
   if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   return parse_begin(exec_ctx, p, cur, end);
 }
@@ -1534,7 +1534,8 @@
 
 /* PUBLIC INTERFACE */
 
-void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p) {
+void grpc_chttp2_hpack_parser_init(grpc_exec_ctx *exec_ctx,
+                                   grpc_chttp2_hpack_parser *p) {
   p->on_header = NULL;
   p->on_header_user_data = NULL;
   p->state = parse_begin;
@@ -1546,7 +1547,7 @@
   p->value.length = 0;
   p->dynamic_table_update_allowed = 2;
   p->last_error = GRPC_ERROR_NONE;
-  grpc_chttp2_hptbl_init(&p->table);
+  grpc_chttp2_hptbl_init(exec_ctx, &p->table);
 }
 
 void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p) {
@@ -1554,8 +1555,9 @@
   p->state = parse_stream_dep0;
 }
 
-void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p) {
-  grpc_chttp2_hptbl_destroy(&p->table);
+void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_hpack_parser *p) {
+  grpc_chttp2_hptbl_destroy(exec_ctx, &p->table);
   GRPC_ERROR_UNREF(p->last_error);
   gpr_free(p->key.str);
   gpr_free(p->value.str);
@@ -1634,10 +1636,11 @@
              however -- it might be that we receive a RST_STREAM following this
              and can avoid the extra write */
           GRPC_CHTTP2_STREAM_REF(s, "final_rst");
-          grpc_combiner_execute_finally(
-              exec_ctx, t->combiner,
-              grpc_closure_create(force_client_rst_stream, s), GRPC_ERROR_NONE,
-              false);
+          grpc_closure_sched(
+              exec_ctx, grpc_closure_create(force_client_rst_stream, s,
+                                            grpc_combiner_finally_scheduler(
+                                                t->combiner, false)),
+              GRPC_ERROR_NONE);
         }
         grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false,
                                        GRPC_ERROR_NONE);
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index a39bf46..52ccf1e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -99,8 +99,10 @@
   grpc_chttp2_hptbl table;
 };
 
-void grpc_chttp2_hpack_parser_init(grpc_chttp2_hpack_parser *p);
-void grpc_chttp2_hpack_parser_destroy(grpc_chttp2_hpack_parser *p);
+void grpc_chttp2_hpack_parser_init(grpc_exec_ctx *exec_ctx,
+                                   grpc_chttp2_hpack_parser *p);
+void grpc_chttp2_hpack_parser_destroy(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_hpack_parser *p);
 
 void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
 
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.c b/src/core/ext/transport/chttp2/transport/hpack_table.c
index 2dc793d..26d4036 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.c
@@ -179,7 +179,7 @@
          GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
 }
 
-void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl) {
+void grpc_chttp2_hptbl_init(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) {
   size_t i;
 
   memset(tbl, 0, sizeof(*tbl));
@@ -190,18 +190,20 @@
   tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
   memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
   for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
-    tbl->static_ents[i - 1] =
-        grpc_mdelem_from_strings(static_table[i].key, static_table[i].value);
+    tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
+        exec_ctx, static_table[i].key, static_table[i].value);
   }
 }
 
-void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
+void grpc_chttp2_hptbl_destroy(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hptbl *tbl) {
   size_t i;
   for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
-    GRPC_MDELEM_UNREF(tbl->static_ents[i]);
+    GRPC_MDELEM_UNREF(exec_ctx, tbl->static_ents[i]);
   }
   for (i = 0; i < tbl->num_ents; i++) {
-    GRPC_MDELEM_UNREF(tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
+    GRPC_MDELEM_UNREF(exec_ctx,
+                      tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
   }
   gpr_free(tbl->ents);
 }
@@ -224,7 +226,7 @@
 }
 
 /* Evict one element from the table */
-static void evict1(grpc_chttp2_hptbl *tbl) {
+static void evict1(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl) {
   grpc_mdelem *first_ent = tbl->ents[tbl->first_ent];
   size_t elem_bytes = GRPC_SLICE_LENGTH(first_ent->key->slice) +
                       GRPC_SLICE_LENGTH(first_ent->value->slice) +
@@ -233,7 +235,7 @@
   tbl->mem_used -= (uint32_t)elem_bytes;
   tbl->first_ent = ((tbl->first_ent + 1) % tbl->cap_entries);
   tbl->num_ents--;
-  GRPC_MDELEM_UNREF(first_ent);
+  GRPC_MDELEM_UNREF(exec_ctx, first_ent);
 }
 
 static void rebuild_ents(grpc_chttp2_hptbl *tbl, uint32_t new_cap) {
@@ -249,7 +251,8 @@
   tbl->first_ent = 0;
 }
 
-void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
+void grpc_chttp2_hptbl_set_max_bytes(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hptbl *tbl,
                                      uint32_t max_bytes) {
   if (tbl->max_bytes == max_bytes) {
     return;
@@ -258,12 +261,13 @@
     gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
   }
   while (tbl->mem_used > max_bytes) {
-    evict1(tbl);
+    evict1(exec_ctx, tbl);
   }
   tbl->max_bytes = max_bytes;
 }
 
-grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx,
+                                                     grpc_chttp2_hptbl *tbl,
                                                      uint32_t bytes) {
   if (tbl->current_table_bytes == bytes) {
     return GRPC_ERROR_NONE;
@@ -281,7 +285,7 @@
     gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
   }
   while (tbl->mem_used > bytes) {
-    evict1(tbl);
+    evict1(exec_ctx, tbl);
   }
   tbl->current_table_bytes = bytes;
   tbl->max_entries = entries_for_bytes(bytes);
@@ -296,7 +300,8 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
   /* determine how many bytes of buffer this entry represents */
   size_t elem_bytes = GRPC_SLICE_LENGTH(md->key->slice) +
                       GRPC_SLICE_LENGTH(md->value->slice) +
@@ -326,14 +331,14 @@
      * empty table.
      */
     while (tbl->num_ents) {
-      evict1(tbl);
+      evict1(exec_ctx, tbl);
     }
     return GRPC_ERROR_NONE;
   }
 
   /* evict entries to ensure no overflow */
   while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
-    evict1(tbl);
+    evict1(exec_ctx, tbl);
   }
 
   /* copy the finalized entry in */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index 2ca130e..144574e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -84,18 +84,21 @@
 } grpc_chttp2_hptbl;
 
 /* initialize a hpack table */
-void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl);
-void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl);
-void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl,
+void grpc_chttp2_hptbl_init(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl);
+void grpc_chttp2_hptbl_destroy(grpc_exec_ctx *exec_ctx, grpc_chttp2_hptbl *tbl);
+void grpc_chttp2_hptbl_set_max_bytes(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hptbl *tbl,
                                      uint32_t max_bytes);
-grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl,
+grpc_error *grpc_chttp2_hptbl_set_current_table_size(grpc_exec_ctx *exec_ctx,
+                                                     grpc_chttp2_hptbl *tbl,
                                                      uint32_t bytes);
 
 /* lookup a table entry based on its hpack index */
 grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
                                       uint32_t index);
 /* add a table entry to the index */
-grpc_error *grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl,
+grpc_error *grpc_chttp2_hptbl_add(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_hptbl *tbl,
                                   grpc_mdelem *md) GRPC_MUST_USE_RESULT;
 /* Find a key/value pair in the table... returns the index in the table of the
    most similar entry, or 0 if the value was not found */
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.c b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
index 3e463a7..5d10949 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.c
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.c
@@ -46,11 +46,11 @@
 }
 
 void grpc_chttp2_incoming_metadata_buffer_destroy(
-    grpc_chttp2_incoming_metadata_buffer *buffer) {
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer) {
   size_t i;
   if (!buffer->published) {
     for (i = 0; i < buffer->count; i++) {
-      GRPC_MDELEM_UNREF(buffer->elems[i].md);
+      GRPC_MDELEM_UNREF(exec_ctx, buffer->elems[i].md);
     }
   }
   gpr_free(buffer->elems);
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index df4343b..7a0c4da 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -49,7 +49,7 @@
 void grpc_chttp2_incoming_metadata_buffer_init(
     grpc_chttp2_incoming_metadata_buffer *buffer);
 void grpc_chttp2_incoming_metadata_buffer_destroy(
-    grpc_chttp2_incoming_metadata_buffer *buffer);
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_metadata_buffer *buffer);
 void grpc_chttp2_incoming_metadata_buffer_publish(
     grpc_chttp2_incoming_metadata_buffer *buffer, grpc_metadata_batch *batch);
 
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index b727965..a52acba 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -212,10 +212,8 @@
 
   grpc_closure write_action_begin_locked;
   grpc_closure write_action;
-  grpc_closure write_action_end;
   grpc_closure write_action_end_locked;
 
-  grpc_closure read_action_begin;
   grpc_closure read_action_locked;
 
   /** incoming read bytes */
@@ -336,10 +334,8 @@
   /** have we scheduled a destructive cleanup? */
   bool destructive_reclaimer_registered;
   /** benign cleanup closure */
-  grpc_closure benign_reclaimer;
   grpc_closure benign_reclaimer_locked;
   /** destructive cleanup closure */
-  grpc_closure destructive_reclaimer;
   grpc_closure destructive_reclaimer_locked;
 };
 
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 5efb497..4fb5dc7 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -336,7 +336,7 @@
 }
 
 static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) {
-  GRPC_MDELEM_UNREF(md);
+  GRPC_MDELEM_UNREF(exec_ctx, md);
 }
 
 static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx,
@@ -477,7 +477,7 @@
     grpc_chttp2_incoming_metadata_buffer_set_deadline(
         &s->metadata_buffer[0],
         gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
-    GRPC_MDELEM_UNREF(md);
+    GRPC_MDELEM_UNREF(exec_ctx, md);
   } else {
     const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
     const size_t metadata_size_limit =
@@ -495,7 +495,7 @@
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
       grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
       s->seen_error = true;
-      GRPC_MDELEM_UNREF(md);
+      GRPC_MDELEM_UNREF(exec_ctx, md);
     } else {
       grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
     }
@@ -538,7 +538,7 @@
             GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
     s->seen_error = true;
-    GRPC_MDELEM_UNREF(md);
+    GRPC_MDELEM_UNREF(exec_ctx, md);
   } else {
     grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md);
   }
@@ -712,7 +712,7 @@
     memcpy(t->settings[GRPC_ACKED_SETTINGS], t->settings[GRPC_SENT_SETTINGS],
            GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
     grpc_chttp2_hptbl_set_max_bytes(
-        &t->hpack_parser.table,
+        exec_ctx, &t->hpack_parser.table,
         t->settings[GRPC_ACKED_SETTINGS]
                    [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
     t->sent_local_settings = 0;
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 139e738..ef2010a 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -39,6 +39,7 @@
 
 #include "src/core/ext/transport/chttp2/transport/http2_errors.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 
 static void add_to_write_list(grpc_chttp2_write_cb **list,
                               grpc_chttp2_write_cb *cb) {
@@ -119,7 +120,7 @@
     /* send initial metadata if it's available */
     if (!sent_initial_metadata && s->send_initial_metadata) {
       grpc_chttp2_encode_header(
-          &t->hpack_compressor, s->id, s->send_initial_metadata, 0,
+          exec_ctx, &t->hpack_compressor, s->id, s->send_initial_metadata, 0,
           t->settings[GRPC_ACKED_SETTINGS][GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
           &s->stats.outgoing, &t->outbuf);
       s->send_initial_metadata = NULL;
@@ -186,9 +187,9 @@
                                   &s->stats.outgoing, &t->outbuf);
         } else {
           grpc_chttp2_encode_header(
-              &t->hpack_compressor, s->id, s->send_trailing_metadata, true,
-              t->settings[GRPC_ACKED_SETTINGS]
-                         [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
+              exec_ctx, &t->hpack_compressor, s->id, s->send_trailing_metadata,
+              true, t->settings[GRPC_ACKED_SETTINGS]
+                               [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE],
               &s->stats.outgoing, &t->outbuf);
         }
         s->send_trailing_metadata = NULL;
@@ -254,7 +255,7 @@
     }
     GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:end");
   }
-  grpc_slice_buffer_reset_and_unref(&t->outbuf);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &t->outbuf);
   GRPC_ERROR_UNREF(error);
   GPR_TIMER_END("grpc_chttp2_end_write", 0);
 }
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index afc59f4..296c406 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -427,6 +427,7 @@
     cronet_bidirectional_stream *stream,
     const cronet_bidirectional_stream_header_array *headers,
     const char *negotiated_protocol) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
              headers, negotiated_protocol);
   stream_obj *s = (stream_obj *)stream->annotation;
@@ -438,7 +439,7 @@
     grpc_chttp2_incoming_metadata_buffer_add(
         &s->state.rs.initial_metadata,
         grpc_mdelem_from_metadata_strings(
-            grpc_mdstr_from_string(headers->headers[i].key),
+            &exec_ctx, grpc_mdstr_from_string(headers->headers[i].key),
             grpc_mdstr_from_string(headers->headers[i].value)));
   }
   s->state.state_callback_received[OP_RECV_INITIAL_METADATA] = true;
@@ -455,6 +456,7 @@
                                      s->state.rs.remaining_bytes);
   }
   gpr_mu_unlock(&s->mu);
+  grpc_exec_ctx_finish(&exec_ctx);
   execute_from_storage(s);
 }
 
@@ -520,6 +522,7 @@
 static void on_response_trailers_received(
     cronet_bidirectional_stream *stream,
     const cronet_bidirectional_stream_header_array *trailers) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   CRONET_LOG(GPR_DEBUG, "R: on_response_trailers_received(%p,%p)", stream,
              trailers);
   stream_obj *s = (stream_obj *)stream->annotation;
@@ -534,7 +537,7 @@
     grpc_chttp2_incoming_metadata_buffer_add(
         &s->state.rs.trailing_metadata,
         grpc_mdelem_from_metadata_strings(
-            grpc_mdstr_from_string(trailers->headers[i].key),
+            &exec_ctx, grpc_mdstr_from_string(trailers->headers[i].key),
             grpc_mdstr_from_string(trailers->headers[i].value)));
     s->state.rs.trailing_metadata_valid = true;
     if (0 == strcmp(trailers->headers[i].key, "grpc-status") &&
@@ -554,8 +557,10 @@
     s->state.state_op_done[OP_SEND_TRAILING_METADATA] = true;
 
     gpr_mu_unlock(&s->mu);
+    grpc_exec_ctx_finish(&exec_ctx);
   } else {
     gpr_mu_unlock(&s->mu);
+    grpc_exec_ctx_finish(&exec_ctx);
     execute_from_storage(s);
   }
 }
@@ -849,17 +854,17 @@
                            OP_RECV_INITIAL_METADATA)) {
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_INITIAL_METADATA", oas);
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
-      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
-                          GRPC_ERROR_CANCELLED, NULL);
+      grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
+                         GRPC_ERROR_CANCELLED);
     } else if (stream_state->state_callback_received[OP_FAILED]) {
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, stream_op->recv_initial_metadata_ready,
-          make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."), NULL);
+          make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."));
     } else {
       grpc_chttp2_incoming_metadata_buffer_publish(
           &oas->s->state.rs.initial_metadata, stream_op->recv_initial_metadata);
-      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
-                          GRPC_ERROR_NONE, NULL);
+      grpc_closure_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
+                         GRPC_ERROR_NONE);
     }
     stream_state->state_op_done[OP_RECV_INITIAL_METADATA] = true;
     result = ACTION_TAKEN_NO_CALLBACK;
@@ -910,22 +915,22 @@
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_MESSAGE", oas);
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
       CRONET_LOG(GPR_DEBUG, "Stream is cancelled.");
-      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
-                          GRPC_ERROR_CANCELLED, NULL);
+      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+                         GRPC_ERROR_CANCELLED);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
     } else if (stream_state->state_callback_received[OP_FAILED]) {
       CRONET_LOG(GPR_DEBUG, "Stream failed.");
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, stream_op->recv_message_ready,
-          make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."), NULL);
+          make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."));
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
     } else if (stream_state->rs.read_stream_closed == true) {
       /* No more data will be received */
       CRONET_LOG(GPR_DEBUG, "read stream closed");
-      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
-                          GRPC_ERROR_NONE, NULL);
+      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+                         GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
       result = ACTION_TAKEN_NO_CALLBACK;
@@ -958,8 +963,8 @@
                                         &stream_state->rs.read_slice_buffer, 0);
           *((grpc_byte_buffer **)stream_op->recv_message) =
               (grpc_byte_buffer *)&stream_state->rs.sbs;
-          grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
-                              GRPC_ERROR_NONE, NULL);
+          grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+                             GRPC_ERROR_NONE);
           stream_state->state_op_done[OP_RECV_MESSAGE] = true;
           oas->state.state_op_done[OP_RECV_MESSAGE] = true;
           result = ACTION_TAKEN_NO_CALLBACK;
@@ -993,8 +998,8 @@
                                     &stream_state->rs.read_slice_buffer, 0);
       *((grpc_byte_buffer **)stream_op->recv_message) =
           (grpc_byte_buffer *)&stream_state->rs.sbs;
-      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
-                          GRPC_ERROR_NONE, NULL);
+      grpc_closure_sched(exec_ctx, stream_op->recv_message_ready,
+                         GRPC_ERROR_NONE);
       stream_state->state_op_done[OP_RECV_MESSAGE] = true;
       oas->state.state_op_done[OP_RECV_MESSAGE] = true;
       /* Do an extra read to trigger on_succeeded() callback in case connection
@@ -1055,18 +1060,17 @@
                            OP_ON_COMPLETE)) {
     CRONET_LOG(GPR_DEBUG, "running: %p  OP_ON_COMPLETE", oas);
     if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
-      grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete,
-                          GRPC_ERROR_REF(stream_state->cancel_error), NULL);
+      grpc_closure_sched(exec_ctx, stream_op->on_complete,
+                         GRPC_ERROR_REF(stream_state->cancel_error));
     } else if (stream_state->state_callback_received[OP_FAILED]) {
-      grpc_exec_ctx_sched(
+      grpc_closure_sched(
           exec_ctx, stream_op->on_complete,
-          make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."), NULL);
+          make_error_with_desc(GRPC_STATUS_UNAVAILABLE, "Unavailable."));
     } else {
       /* All actions in this stream_op are complete. Call the on_complete
        * callback
        */
-      grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete, GRPC_ERROR_NONE,
-                          NULL);
+      grpc_closure_sched(exec_ctx, stream_op->on_complete, GRPC_ERROR_NONE);
     }
     oas->state.state_op_done[OP_ON_COMPLETE] = true;
     oas->done = true;
diff --git a/src/core/lib/README.md b/src/core/lib/README.md
new file mode 100644
index 0000000..69b6bce
--- /dev/null
+++ b/src/core/lib/README.md
@@ -0,0 +1,6 @@
+Required elements of gRPC Core: Each module in this directory is required to
+build gRPC. If it's possible to envisage a configuration where code is not
+required, then that code belongs in ext/ instead.
+
+NOTE: The movement of code between lib and ext is an ongoing effort, so this
+directory currently contains too much of the core library.
diff --git a/src/core/lib/channel/README.md b/src/core/lib/channel/README.md
new file mode 100644
index 0000000..2dfcfe6
--- /dev/null
+++ b/src/core/lib/channel/README.md
@@ -0,0 +1,4 @@
+# Channel
+
+Provides channel/call stack implementation, and implementation of common filters
+for that implementation.
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 401a2ad..1a099ac 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -184,7 +184,7 @@
   return b;
 }
 
-void grpc_channel_args_destroy(grpc_channel_args *a) {
+void grpc_channel_args_destroy(grpc_exec_ctx *exec_ctx, grpc_channel_args *a) {
   size_t i;
   if (!a) return;
   for (i = 0; i < a->num_args; i++) {
@@ -195,7 +195,8 @@
       case GRPC_ARG_INTEGER:
         break;
       case GRPC_ARG_POINTER:
-        a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
+        a->args[i].value.pointer.vtable->destroy(exec_ctx,
+                                                 a->args[i].value.pointer.p);
         break;
     }
     gpr_free(a->args[i].key);
@@ -249,7 +250,8 @@
 }
 
 grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
-    grpc_channel_args **a, grpc_compression_algorithm algorithm, int state) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_args **a,
+    grpc_compression_algorithm algorithm, int state) {
   int *states_arg = NULL;
   grpc_channel_args *result = *a;
   const int states_arg_found =
@@ -282,7 +284,7 @@
       GPR_BITCLEAR((unsigned *)&tmp.value.integer, algorithm);
     }
     result = grpc_channel_args_copy_and_add(*a, &tmp, 1);
-    grpc_channel_args_destroy(*a);
+    grpc_channel_args_destroy(exec_ctx, *a);
     *a = result;
   }
   return result;
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 88fc0e3..5c7d31f 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -68,7 +68,7 @@
                                            const grpc_channel_args *b);
 
 /** Destroy arguments created by \a grpc_channel_args_copy */
-void grpc_channel_args_destroy(grpc_channel_args *a);
+void grpc_channel_args_destroy(grpc_exec_ctx *exec_ctx, grpc_channel_args *a);
 
 /** Returns the compression algorithm set in \a a. */
 grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
@@ -88,7 +88,8 @@
  * modified to point to the returned instance (which may be different from the
  * input value of \a a). */
 grpc_channel_args *grpc_channel_args_compression_algorithm_set_state(
-    grpc_channel_args **a, grpc_compression_algorithm algorithm, int enabled);
+    grpc_exec_ctx *exec_ctx, grpc_channel_args **a,
+    grpc_compression_algorithm algorithm, int enabled);
 
 /** Returns the bitset representing the support state (true for enabled, false
  * for disabled) for compression algorithms.
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 999ad5f..8f08b42 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -102,13 +102,11 @@
   return CALL_ELEMS_FROM_STACK(call_stack) + index;
 }
 
-void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
-                             grpc_iomgr_cb_func destroy, void *destroy_arg,
-                             const grpc_channel_filter **filters,
-                             size_t filter_count,
-                             const grpc_channel_args *channel_args,
-                             grpc_transport *optional_transport,
-                             const char *name, grpc_channel_stack *stack) {
+grpc_error *grpc_channel_stack_init(
+    grpc_exec_ctx *exec_ctx, int initial_refs, grpc_iomgr_cb_func destroy,
+    void *destroy_arg, const grpc_channel_filter **filters, size_t filter_count,
+    const grpc_channel_args *channel_args, grpc_transport *optional_transport,
+    const char *name, grpc_channel_stack *stack) {
   size_t call_size =
       ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(grpc_call_stack)) +
       ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_call_element));
@@ -126,6 +124,7 @@
       ROUND_UP_TO_ALIGNMENT_SIZE(filter_count * sizeof(grpc_channel_element));
 
   /* init per-filter data */
+  grpc_error *first_error = GRPC_ERROR_NONE;
   for (i = 0; i < filter_count; i++) {
     args.channel_stack = stack;
     args.channel_args = channel_args;
@@ -134,7 +133,15 @@
     args.is_last = i == (filter_count - 1);
     elems[i].filter = filters[i];
     elems[i].channel_data = user_data;
-    elems[i].filter->init_channel_elem(exec_ctx, &elems[i], &args);
+    grpc_error *error =
+        elems[i].filter->init_channel_elem(exec_ctx, &elems[i], &args);
+    if (error != GRPC_ERROR_NONE) {
+      if (first_error == GRPC_ERROR_NONE) {
+        first_error = error;
+      } else {
+        GRPC_ERROR_UNREF(error);
+      }
+    }
     user_data += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_channel_data);
     call_size += ROUND_UP_TO_ALIGNMENT_SIZE(filters[i]->sizeof_call_data);
   }
@@ -144,6 +151,7 @@
              grpc_channel_stack_size(filters, filter_count));
 
   stack->call_stack_size = call_size;
+  return first_error;
 }
 
 void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
@@ -289,7 +297,8 @@
   grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
   memset(op, 0, sizeof(*op));
   op->cancel_error = GRPC_ERROR_CANCELLED;
-  op->on_complete = grpc_closure_create(destroy_op, op);
+  op->on_complete =
+      grpc_closure_create(destroy_op, op, grpc_schedule_on_exec_ctx);
   elem->filter->start_transport_stream_op(exec_ctx, elem, op);
 }
 
@@ -299,8 +308,9 @@
                                                 grpc_slice *optional_message) {
   grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
   memset(op, 0, sizeof(*op));
-  op->on_complete = grpc_closure_create(destroy_op, op);
-  grpc_transport_stream_op_add_cancellation_with_message(op, status,
+  op->on_complete =
+      grpc_closure_create(destroy_op, op, grpc_schedule_on_exec_ctx);
+  grpc_transport_stream_op_add_cancellation_with_message(exec_ctx, op, status,
                                                          optional_message);
   elem->filter->start_transport_stream_op(exec_ctx, elem, op);
 }
@@ -311,7 +321,8 @@
                                                grpc_slice *optional_message) {
   grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
   memset(op, 0, sizeof(*op));
-  op->on_complete = grpc_closure_create(destroy_op, op);
-  grpc_transport_stream_op_add_close(op, status, optional_message);
+  op->on_complete =
+      grpc_closure_create(destroy_op, op, grpc_schedule_on_exec_ctx);
+  grpc_transport_stream_op_add_close(exec_ctx, op, status, optional_message);
   elem->filter->start_transport_stream_op(exec_ctx, elem, op);
 }
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 004643d..d9d3a85 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -34,6 +34,13 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H
 #define GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H
 
+//////////////////////////////////////////////////////////////////////////////
+// IMPORTANT NOTE:
+//
+// When you update this API, please make the corresponding changes to
+// the C++ API in src/cpp/common/channel_filter.{h,cc}
+//////////////////////////////////////////////////////////////////////////////
+
 /* A channel filter defines how operations on a channel are implemented.
    Channel filters are chained together to create full channels, and if those
    chains are linear, then channel stacks provide a mechanism to minimize
@@ -146,8 +153,9 @@
      is_first, is_last designate this elements position in the stack, and are
      useful for asserting correct configuration by upper layer code.
      The filter does not need to do any chaining */
-  void (*init_channel_elem)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
-                            grpc_channel_element_args *args);
+  grpc_error *(*init_channel_elem)(grpc_exec_ctx *exec_ctx,
+                                   grpc_channel_element *elem,
+                                   grpc_channel_element_args *args);
   /* Destroy per channel data.
      The filter does not need to do any chaining */
   void (*destroy_channel_elem)(grpc_exec_ctx *exec_ctx,
@@ -214,12 +222,11 @@
 size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
                                size_t filter_count);
 /* Initialize a channel stack given some filters */
-void grpc_channel_stack_init(grpc_exec_ctx *exec_ctx, int initial_refs,
-                             grpc_iomgr_cb_func destroy, void *destroy_arg,
-                             const grpc_channel_filter **filters,
-                             size_t filter_count, const grpc_channel_args *args,
-                             grpc_transport *optional_transport,
-                             const char *name, grpc_channel_stack *stack);
+grpc_error *grpc_channel_stack_init(
+    grpc_exec_ctx *exec_ctx, int initial_refs, grpc_iomgr_cb_func destroy,
+    void *destroy_arg, const grpc_channel_filter **filters, size_t filter_count,
+    const grpc_channel_args *args, grpc_transport *optional_transport,
+    const char *name, grpc_channel_stack *stack);
 /* Destroy a channel stack */
 void grpc_channel_stack_destroy(grpc_exec_ctx *exec_ctx,
                                 grpc_channel_stack *stack);
diff --git a/src/core/lib/channel/channel_stack_builder.c b/src/core/lib/channel/channel_stack_builder.c
index eda4968..5f9e3b4 100644
--- a/src/core/lib/channel/channel_stack_builder.c
+++ b/src/core/lib/channel/channel_stack_builder.c
@@ -138,9 +138,10 @@
 }
 
 void grpc_channel_stack_builder_set_channel_arguments(
-    grpc_channel_stack_builder *builder, const grpc_channel_args *args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder,
+    const grpc_channel_args *args) {
   if (builder->args != NULL) {
-    grpc_channel_args_destroy(builder->args);
+    grpc_channel_args_destroy(exec_ctx, builder->args);
   }
   builder->args = grpc_channel_args_copy(args);
 }
@@ -213,7 +214,8 @@
   return true;
 }
 
-void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder) {
+void grpc_channel_stack_builder_destroy(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_stack_builder *builder) {
   filter_node *p = builder->begin.next;
   while (p != &builder->end) {
     filter_node *next = p->next;
@@ -221,17 +223,16 @@
     p = next;
   }
   if (builder->args != NULL) {
-    grpc_channel_args_destroy(builder->args);
+    grpc_channel_args_destroy(exec_ctx, builder->args);
   }
   gpr_free(builder->target);
   gpr_free(builder);
 }
 
-void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
-                                        grpc_channel_stack_builder *builder,
-                                        size_t prefix_bytes, int initial_refs,
-                                        grpc_iomgr_cb_func destroy,
-                                        void *destroy_arg) {
+grpc_error *grpc_channel_stack_builder_finish(
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder,
+    size_t prefix_bytes, int initial_refs, grpc_iomgr_cb_func destroy,
+    void *destroy_arg, void **result) {
   // count the number of filters
   size_t num_filters = 0;
   for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
@@ -250,28 +251,35 @@
   size_t channel_stack_size = grpc_channel_stack_size(filters, num_filters);
 
   // allocate memory, with prefix_bytes followed by channel_stack_size
-  char *result = gpr_malloc(prefix_bytes + channel_stack_size);
+  *result = gpr_malloc(prefix_bytes + channel_stack_size);
   // fetch a pointer to the channel stack
   grpc_channel_stack *channel_stack =
-      (grpc_channel_stack *)(result + prefix_bytes);
+      (grpc_channel_stack *)((char *)(*result) + prefix_bytes);
   // and initialize it
-  grpc_channel_stack_init(exec_ctx, initial_refs, destroy,
-                          destroy_arg == NULL ? result : destroy_arg, filters,
-                          num_filters, builder->args, builder->transport,
-                          builder->name, channel_stack);
+  grpc_error *error = grpc_channel_stack_init(
+      exec_ctx, initial_refs, destroy,
+      destroy_arg == NULL ? *result : destroy_arg, filters, num_filters,
+      builder->args, builder->transport, builder->name, channel_stack);
 
-  // run post-initialization functions
-  i = 0;
-  for (filter_node *p = builder->begin.next; p != &builder->end; p = p->next) {
-    if (p->init != NULL) {
-      p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
-              p->init_arg);
+  if (error != GRPC_ERROR_NONE) {
+    grpc_channel_stack_destroy(exec_ctx, channel_stack);
+    gpr_free(*result);
+    *result = NULL;
+  } else {
+    // run post-initialization functions
+    i = 0;
+    for (filter_node *p = builder->begin.next; p != &builder->end;
+         p = p->next) {
+      if (p->init != NULL) {
+        p->init(channel_stack, grpc_channel_stack_element(channel_stack, i),
+                p->init_arg);
+      }
+      i++;
     }
-    i++;
   }
 
-  grpc_channel_stack_builder_destroy(builder);
+  grpc_channel_stack_builder_destroy(exec_ctx, builder);
   gpr_free((grpc_channel_filter **)filters);
 
-  return result;
+  return error;
 }
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index 4a00f7b..8adf38e 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -73,7 +73,8 @@
 
 /// Set channel arguments: copies args
 void grpc_channel_stack_builder_set_channel_arguments(
-    grpc_channel_stack_builder *builder, const grpc_channel_args *args);
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder,
+    const grpc_channel_args *args);
 
 /// Return a borrowed pointer to the channel arguments
 const grpc_channel_args *grpc_channel_stack_builder_get_channel_arguments(
@@ -146,19 +147,19 @@
 void grpc_channel_stack_builder_iterator_destroy(
     grpc_channel_stack_builder_iterator *iterator);
 
-/// Destroy the builder, return the freshly minted channel stack
+/// Destroy the builder, return the freshly minted channel stack in \a result.
 /// Allocates \a prefix_bytes bytes before the channel stack
 /// Returns the base pointer of the allocated block
 /// \a initial_refs, \a destroy, \a destroy_arg are as per
 /// grpc_channel_stack_init
-void *grpc_channel_stack_builder_finish(grpc_exec_ctx *exec_ctx,
-                                        grpc_channel_stack_builder *builder,
-                                        size_t prefix_bytes, int initial_refs,
-                                        grpc_iomgr_cb_func destroy,
-                                        void *destroy_arg);
+grpc_error *grpc_channel_stack_builder_finish(
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder,
+    size_t prefix_bytes, int initial_refs, grpc_iomgr_cb_func destroy,
+    void *destroy_arg, void **result);
 
 /// Destroy the builder without creating a channel stack
-void grpc_channel_stack_builder_destroy(grpc_channel_stack_builder *builder);
+void grpc_channel_stack_builder_destroy(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_stack_builder *builder);
 
 extern int grpc_trace_channel_stack_builder;
 
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 2874d63..337c194 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -44,6 +44,7 @@
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/compression/message_compress.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/static_metadata.h"
 
@@ -82,7 +83,8 @@
 /** For each \a md element from the incoming metadata, filter out the entry for
  * "grpc-encoding", using its value to populate the call data's
  * compression_algorithm field. */
-static grpc_mdelem *compression_md_filter(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *compression_md_filter(grpc_exec_ctx *exec_ctx,
+                                          void *user_data, grpc_mdelem *md) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -130,12 +132,14 @@
 
 /** Filter initial metadata */
 static void process_send_initial_metadata(
-    grpc_call_element *elem, grpc_metadata_batch *initial_metadata) {
+    grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+    grpc_metadata_batch *initial_metadata) {
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
   /* Parse incoming request for compression. If any, it'll be available
    * at calld->compression_algorithm */
-  grpc_metadata_batch_filter(initial_metadata, compression_md_filter, elem);
+  grpc_metadata_batch_filter(exec_ctx, initial_metadata, compression_md_filter,
+                             elem);
   if (!calld->has_compression_algorithm) {
     /* If no algorithm was found in the metadata and we aren't
      * exceptionally skipping compression, fall back to the channel
@@ -161,7 +165,7 @@
 static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
   grpc_call_element *elem = elemp;
   call_data *calld = elem->call_data;
-  grpc_slice_buffer_reset_and_unref(&calld->slices);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices);
   calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
 }
 
@@ -171,8 +175,8 @@
   int did_compress;
   grpc_slice_buffer tmp;
   grpc_slice_buffer_init(&tmp);
-  did_compress =
-      grpc_msg_compress(calld->compression_algorithm, &calld->slices, &tmp);
+  did_compress = grpc_msg_compress(exec_ctx, calld->compression_algorithm,
+                                   &calld->slices, &tmp);
   if (did_compress) {
     if (grpc_compression_trace) {
       char *algo_name;
@@ -199,7 +203,7 @@
     }
   }
 
-  grpc_slice_buffer_destroy(&tmp);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &tmp);
 
   grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
                                 calld->send_flags);
@@ -243,7 +247,7 @@
   GPR_TIMER_BEGIN("compress_start_transport_stream_op", 0);
 
   if (op->send_initial_metadata) {
-    process_send_initial_metadata(elem, op->send_initial_metadata);
+    process_send_initial_metadata(exec_ctx, elem, op->send_initial_metadata);
   }
   if (op->send_message != NULL &&
       !skip_compression(elem, op->send_message->flags)) {
@@ -269,8 +273,10 @@
   /* initialize members */
   grpc_slice_buffer_init(&calld->slices);
   calld->has_compression_algorithm = 0;
-  grpc_closure_init(&calld->got_slice, got_slice, elem);
-  grpc_closure_init(&calld->send_done, send_done, elem);
+  grpc_closure_init(&calld->got_slice, got_slice, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&calld->send_done, send_done, elem,
+                    grpc_schedule_on_exec_ctx);
 
   return GRPC_ERROR_NONE;
 }
@@ -281,13 +287,13 @@
                               void *ignored) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
-  grpc_slice_buffer_destroy(&calld->slices);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   channel_data *channeld = elem->channel_data;
 
   channeld->enabled_algorithms_bitset =
@@ -315,6 +321,7 @@
   }
 
   GPR_ASSERT(!args->is_last);
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel data */
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 038e819..ccc0619 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -114,12 +114,13 @@
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   channel_data *cd = (channel_data *)elem->channel_data;
   GPR_ASSERT(args->is_last);
   cd->transport = NULL;
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel_data */
@@ -170,7 +171,8 @@
   channel_stack->call_stack_size += grpc_transport_stream_size(t);
 }
 
-bool grpc_add_connected_filter(grpc_channel_stack_builder *builder,
+bool grpc_add_connected_filter(grpc_exec_ctx *exec_ctx,
+                               grpc_channel_stack_builder *builder,
                                void *arg_must_be_null) {
   GPR_ASSERT(arg_must_be_null == NULL);
   grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h
index 3142d64..3585c0e 100644
--- a/src/core/lib/channel/connected_channel.h
+++ b/src/core/lib/channel/connected_channel.h
@@ -36,7 +36,8 @@
 
 #include "src/core/lib/channel/channel_stack_builder.h"
 
-bool grpc_add_connected_filter(grpc_channel_stack_builder *builder,
+bool grpc_add_connected_filter(grpc_exec_ctx *exec_ctx,
+                               grpc_channel_stack_builder *builder,
                                void *arg_must_be_null);
 
 #endif /* GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h
index 071c5f6..6c931ad 100644
--- a/src/core/lib/channel/context.h
+++ b/src/core/lib/channel/context.h
@@ -47,6 +47,9 @@
   /// Value is a \a census_context.
   GRPC_CONTEXT_TRACING,
 
+  /// Reserved for traffic_class_context.
+  GRPC_CONTEXT_TRAFFIC,
+
   GRPC_CONTEXT_COUNT
 } grpc_context_index;
 
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index 0e703d8..a45a4d4 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -41,6 +41,7 @@
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/slice/slice_internal.h"
 
 //
 // grpc_deadline_state
@@ -58,7 +59,7 @@
     grpc_slice msg = grpc_slice_from_static_string("Deadline Exceeded");
     grpc_call_element_send_cancel_with_message(
         exec_ctx, elem, GRPC_STATUS_DEADLINE_EXCEEDED, &msg);
-    grpc_slice_unref(msg);
+    grpc_slice_unref_internal(exec_ctx, msg);
   }
   GRPC_CALL_STACK_UNREF(exec_ctx, deadline_state->call_stack, "deadline_timer");
 }
@@ -82,8 +83,11 @@
     // Take a reference to the call stack, to be owned by the timer.
     GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
     deadline_state->timer_pending = true;
-    grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback,
-                    elem, gpr_now(GPR_CLOCK_MONOTONIC));
+    grpc_closure_init(&deadline_state->timer_callback, timer_callback, elem,
+                      grpc_schedule_on_exec_ctx);
+    grpc_timer_init(exec_ctx, &deadline_state->timer, deadline,
+                    &deadline_state->timer_callback,
+                    gpr_now(GPR_CLOCK_MONOTONIC));
   }
 }
 static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,
@@ -123,7 +127,8 @@
 static void inject_on_complete_cb(grpc_deadline_state* deadline_state,
                                   grpc_transport_stream_op* op) {
   deadline_state->next_on_complete = op->on_complete;
-  grpc_closure_init(&deadline_state->on_complete, on_complete, deadline_state);
+  grpc_closure_init(&deadline_state->on_complete, on_complete, deadline_state,
+                    grpc_schedule_on_exec_ctx);
   op->on_complete = &deadline_state->on_complete;
 }
 
@@ -172,8 +177,9 @@
     struct start_timer_after_init_state* state = gpr_malloc(sizeof(*state));
     state->elem = elem;
     state->deadline = deadline;
-    grpc_closure_init(&state->closure, start_timer_after_init, state);
-    grpc_exec_ctx_sched(exec_ctx, &state->closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_init(&state->closure, start_timer_after_init, state,
+                      grpc_schedule_on_exec_ctx);
+    grpc_closure_sched(exec_ctx, &state->closure, GRPC_ERROR_NONE);
   }
 }
 
@@ -207,10 +213,11 @@
 //
 
 // Constructor for channel_data.  Used for both client and server filters.
-static void init_channel_elem(grpc_exec_ctx* exec_ctx,
-                              grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
+static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
+                                     grpc_channel_element* elem,
+                                     grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
+  return GRPC_ERROR_NONE;
 }
 
 // Destructor for channel_data.  Used for both client and server filters.
@@ -289,7 +296,8 @@
       calld->next_recv_initial_metadata_ready = op->recv_initial_metadata_ready;
       calld->recv_initial_metadata = op->recv_initial_metadata;
       grpc_closure_init(&calld->recv_initial_metadata_ready,
-                        recv_initial_metadata_ready, elem);
+                        recv_initial_metadata_ready, elem,
+                        grpc_schedule_on_exec_ctx);
       op->recv_initial_metadata_ready = &calld->recv_initial_metadata_ready;
     }
     // Make sure we know when the call is complete, so that we can cancel
diff --git a/src/core/lib/channel/deadline_filter.h b/src/core/lib/channel/deadline_filter.h
index 716a852..bd2b84f 100644
--- a/src/core/lib/channel/deadline_filter.h
+++ b/src/core/lib/channel/deadline_filter.h
@@ -46,6 +46,7 @@
   bool timer_pending;
   // The deadline timer.
   grpc_timer timer;
+  grpc_closure timer_callback;
   // Closure to invoke when the call is complete.
   // We use this to cancel the timer.
   grpc_closure on_complete;
diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c
index 23edc82..c052ca5 100644
--- a/src/core/lib/channel/handshaker.c
+++ b/src/core/lib/channel/handshaker.c
@@ -86,6 +86,7 @@
   grpc_tcp_server_acceptor* acceptor;
   // Deadline timer across all handshakers.
   grpc_timer deadline_timer;
+  grpc_closure on_timeout;
   // The final callback and user_data to invoke after the last handshaker.
   grpc_closure on_handshake_done;
   void* user_data;
@@ -165,7 +166,7 @@
     // Cancel deadline timer, since we're invoking the on_handshake_done
     // callback now.
     grpc_timer_cancel(exec_ctx, &mgr->deadline_timer);
-    grpc_exec_ctx_sched(exec_ctx, &mgr->on_handshake_done, error, NULL);
+    grpc_closure_sched(exec_ctx, &mgr->on_handshake_done, error);
     mgr->shutdown = true;
   } else {
     grpc_handshaker_do_handshake(exec_ctx, mgr->handshakers[mgr->index],
@@ -218,13 +219,17 @@
   grpc_slice_buffer_init(mgr->args.read_buffer);
   // Initialize state needed for calling handshakers.
   mgr->acceptor = acceptor;
-  grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr);
-  grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args);
+  grpc_closure_init(&mgr->call_next_handshaker, call_next_handshaker, mgr,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&mgr->on_handshake_done, on_handshake_done, &mgr->args,
+                    grpc_schedule_on_exec_ctx);
   // Start deadline timer, which owns a ref.
   gpr_ref(&mgr->refs);
+  grpc_closure_init(&mgr->on_timeout, on_timeout, mgr,
+                    grpc_schedule_on_exec_ctx);
   grpc_timer_init(exec_ctx, &mgr->deadline_timer,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &mgr->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
   // Start first handshaker, which also owns a ref.
   gpr_ref(&mgr->refs);
   bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE);
diff --git a/src/core/lib/channel/handshaker_factory.c b/src/core/lib/channel/handshaker_factory.c
new file mode 100644
index 0000000..3c30a4e
--- /dev/null
+++ b/src/core/lib/channel/handshaker_factory.c
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/handshaker_factory.h"
+
+#include <grpc/support/log.h>
+
+void grpc_handshaker_factory_add_handshakers(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory,
+    const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) {
+  if (handshaker_factory != NULL) {
+    GPR_ASSERT(handshaker_factory->vtable != NULL);
+    handshaker_factory->vtable->add_handshakers(exec_ctx, handshaker_factory,
+                                                args, handshake_mgr);
+  }
+}
+
+void grpc_handshaker_factory_destroy(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory) {
+  if (handshaker_factory != NULL) {
+    GPR_ASSERT(handshaker_factory->vtable != NULL);
+    handshaker_factory->vtable->destroy(exec_ctx, handshaker_factory);
+  }
+}
diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h
new file mode 100644
index 0000000..1984546
--- /dev/null
+++ b/src/core/lib/channel/handshaker_factory.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H
+#define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+// A handshaker factory is used to create handshakers.
+
+typedef struct grpc_handshaker_factory grpc_handshaker_factory;
+
+typedef struct {
+  void (*add_handshakers)(grpc_exec_ctx *exec_ctx,
+                          grpc_handshaker_factory *handshaker_factory,
+                          const grpc_channel_args *args,
+                          grpc_handshake_manager *handshake_mgr);
+  void (*destroy)(grpc_exec_ctx *exec_ctx,
+                  grpc_handshaker_factory *handshaker_factory);
+} grpc_handshaker_factory_vtable;
+
+struct grpc_handshaker_factory {
+  const grpc_handshaker_factory_vtable *vtable;
+};
+
+void grpc_handshaker_factory_add_handshakers(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory,
+    const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr);
+
+void grpc_handshaker_factory_destroy(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H */
diff --git a/src/core/lib/channel/handshaker_registry.c b/src/core/lib/channel/handshaker_registry.c
new file mode 100644
index 0000000..2e5f040
--- /dev/null
+++ b/src/core/lib/channel/handshaker_registry.c
@@ -0,0 +1,113 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/channel/handshaker_registry.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+//
+// grpc_handshaker_factory_list
+//
+
+typedef struct {
+  grpc_handshaker_factory** list;
+  size_t num_factories;
+} grpc_handshaker_factory_list;
+
+static void grpc_handshaker_factory_list_register(
+    grpc_handshaker_factory_list* list, bool at_start,
+    grpc_handshaker_factory* factory) {
+  list->list = gpr_realloc(
+      list->list, (list->num_factories + 1) * sizeof(grpc_handshaker_factory*));
+  if (at_start) {
+    memmove(list->list + 1, list->list,
+            sizeof(grpc_handshaker_factory*) * list->num_factories);
+    list->list[0] = factory;
+  } else {
+    list->list[list->num_factories] = factory;
+  }
+  ++list->num_factories;
+}
+
+static void grpc_handshaker_factory_list_add_handshakers(
+    grpc_exec_ctx* exec_ctx, grpc_handshaker_factory_list* list,
+    const grpc_channel_args* args, grpc_handshake_manager* handshake_mgr) {
+  for (size_t i = 0; i < list->num_factories; ++i) {
+    grpc_handshaker_factory_add_handshakers(exec_ctx, list->list[i], args,
+                                            handshake_mgr);
+  }
+}
+
+static void grpc_handshaker_factory_list_destroy(
+    grpc_exec_ctx* exec_ctx, grpc_handshaker_factory_list* list) {
+  for (size_t i = 0; i < list->num_factories; ++i) {
+    grpc_handshaker_factory_destroy(exec_ctx, list->list[i]);
+  }
+  gpr_free(list->list);
+}
+
+//
+// plugin
+//
+
+static grpc_handshaker_factory_list
+    g_handshaker_factory_lists[NUM_HANDSHAKER_TYPES];
+
+void grpc_handshaker_factory_registry_init() {
+  memset(g_handshaker_factory_lists, 0, sizeof(g_handshaker_factory_lists));
+}
+
+void grpc_handshaker_factory_registry_shutdown(grpc_exec_ctx* exec_ctx) {
+  for (size_t i = 0; i < NUM_HANDSHAKER_TYPES; ++i) {
+    grpc_handshaker_factory_list_destroy(exec_ctx,
+                                         &g_handshaker_factory_lists[i]);
+  }
+}
+
+void grpc_handshaker_factory_register(bool at_start,
+                                      grpc_handshaker_type handshaker_type,
+                                      grpc_handshaker_factory* factory) {
+  grpc_handshaker_factory_list_register(
+      &g_handshaker_factory_lists[handshaker_type], at_start, factory);
+}
+
+void grpc_handshakers_add(grpc_exec_ctx* exec_ctx,
+                          grpc_handshaker_type handshaker_type,
+                          const grpc_channel_args* args,
+                          grpc_handshake_manager* handshake_mgr) {
+  grpc_handshaker_factory_list_add_handshakers(
+      exec_ctx, &g_handshaker_factory_lists[handshaker_type], args,
+      handshake_mgr);
+}
diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h
new file mode 100644
index 0000000..53c1b17
--- /dev/null
+++ b/src/core/lib/channel/handshaker_registry.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H
+#define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/channel/handshaker_factory.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+typedef enum {
+  HANDSHAKER_CLIENT = 0,
+  HANDSHAKER_SERVER,
+  NUM_HANDSHAKER_TYPES,  // Must be last.
+} grpc_handshaker_type;
+
+void grpc_handshaker_factory_registry_init();
+void grpc_handshaker_factory_registry_shutdown(grpc_exec_ctx* exec_ctx);
+
+/// Registers a new handshaker factory.  Takes ownership.
+/// If \a at_start is true, the new handshaker will be at the beginning of
+/// the list.  Otherwise, it will be added to the end.
+void grpc_handshaker_factory_register(bool at_start,
+                                      grpc_handshaker_type handshaker_type,
+                                      grpc_handshaker_factory* factory);
+
+void grpc_handshakers_add(grpc_exec_ctx* exec_ctx,
+                          grpc_handshaker_type handshaker_type,
+                          const grpc_channel_args* args,
+                          grpc_handshake_manager* handshake_mgr);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index fd8b46a..d154450 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -37,6 +37,7 @@
 #include <string.h>
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/percent_encoding.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/transport_impl.h"
@@ -92,13 +93,9 @@
   size_t max_payload_size_for_get;
 } channel_data;
 
-typedef struct {
-  grpc_call_element *elem;
-  grpc_exec_ctx *exec_ctx;
-} client_recv_filter_args;
-
-static grpc_mdelem *client_recv_filter(void *user_data, grpc_mdelem *md) {
-  client_recv_filter_args *a = user_data;
+static grpc_mdelem *client_recv_filter(grpc_exec_ctx *exec_ctx, void *user_data,
+                                       grpc_mdelem *md) {
+  grpc_call_element *elem = user_data;
   if (md == GRPC_MDELEM_STATUS_200) {
     return NULL;
   } else if (md->key == GRPC_MDSTR_STATUS) {
@@ -107,18 +104,19 @@
                  grpc_mdstr_as_c_string(md->value));
     grpc_slice message = grpc_slice_from_copied_string(message_string);
     gpr_free(message_string);
-    grpc_call_element_send_close_with_message(a->exec_ctx, a->elem,
+    grpc_call_element_send_close_with_message(exec_ctx, elem,
                                               GRPC_STATUS_CANCELLED, &message);
     return NULL;
   } else if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
     grpc_slice pct_decoded_msg =
         grpc_permissive_percent_decode_slice(md->value->slice);
     if (grpc_slice_is_equivalent(pct_decoded_msg, md->value->slice)) {
-      grpc_slice_unref(pct_decoded_msg);
+      grpc_slice_unref_internal(exec_ctx, pct_decoded_msg);
       return md;
     } else {
       return grpc_mdelem_from_metadata_strings(
-          GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_decoded_msg));
+          exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+          grpc_mdstr_from_slice(exec_ctx, pct_decoded_msg));
     }
   } else if (md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
     return NULL;
@@ -147,11 +145,8 @@
                                         void *user_data, grpc_error *error) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
-  client_recv_filter_args a;
-  a.elem = elem;
-  a.exec_ctx = exec_ctx;
-  grpc_metadata_batch_filter(calld->recv_initial_metadata, client_recv_filter,
-                             &a);
+  grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
+                             client_recv_filter, elem);
   grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata,
                    GRPC_ERROR_REF(error));
 }
@@ -160,11 +155,8 @@
                                          void *user_data, grpc_error *error) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
-  client_recv_filter_args a;
-  a.elem = elem;
-  a.exec_ctx = exec_ctx;
-  grpc_metadata_batch_filter(calld->recv_trailing_metadata, client_recv_filter,
-                             &a);
+  grpc_metadata_batch_filter(exec_ctx, calld->recv_trailing_metadata,
+                             client_recv_filter, elem);
   grpc_closure_run(exec_ctx, calld->on_done_recv_trailing_metadata,
                    GRPC_ERROR_REF(error));
 }
@@ -183,11 +175,12 @@
 static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
   grpc_call_element *elem = elemp;
   call_data *calld = elem->call_data;
-  grpc_slice_buffer_reset_and_unref(&calld->slices);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &calld->slices);
   calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
 }
 
-static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *client_strip_filter(grpc_exec_ctx *exec_ctx,
+                                        void *user_data, grpc_mdelem *md) {
   /* eat the things we'd like to set ourselves */
   if (md->key == GRPC_MDSTR_METHOD) return NULL;
   if (md->key == GRPC_MDSTR_SCHEME) return NULL;
@@ -275,7 +268,7 @@
         /* when all the send_message data is available, then create a MDELEM and
         append to headers */
         grpc_mdelem *payload_bin = grpc_mdelem_from_metadata_strings(
-            GRPC_MDSTR_GRPC_PAYLOAD_BIN,
+            exec_ctx, GRPC_MDSTR_GRPC_PAYLOAD_BIN,
             grpc_mdstr_from_buffer(calld->payload_bytes,
                                    op->send_message->length));
         grpc_metadata_batch_add_tail(op->send_initial_metadata,
@@ -292,8 +285,8 @@
       }
     }
 
-    grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter,
-                               elem);
+    grpc_metadata_batch_filter(exec_ctx, op->send_initial_metadata,
+                               client_strip_filter, elem);
     /* Send : prefixed headers, which have to be before any application
        layer headers. */
     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
@@ -352,12 +345,17 @@
   calld->send_message_blocked = false;
   grpc_slice_buffer_init(&calld->slices);
   grpc_closure_init(&calld->hc_on_recv_initial_metadata,
-                    hc_on_recv_initial_metadata, elem);
+                    hc_on_recv_initial_metadata, elem,
+                    grpc_schedule_on_exec_ctx);
   grpc_closure_init(&calld->hc_on_recv_trailing_metadata,
-                    hc_on_recv_trailing_metadata, elem);
-  grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem);
-  grpc_closure_init(&calld->got_slice, got_slice, elem);
-  grpc_closure_init(&calld->send_done, send_done, elem);
+                    hc_on_recv_trailing_metadata, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&calld->got_slice, got_slice, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&calld->send_done, send_done, elem,
+                    grpc_schedule_on_exec_ctx);
   return GRPC_ERROR_NONE;
 }
 
@@ -366,7 +364,7 @@
                               const grpc_call_final_info *final_info,
                               void *ignored) {
   call_data *calld = elem->call_data;
-  grpc_slice_buffer_destroy(&calld->slices);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &calld->slices);
 }
 
 static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
@@ -457,9 +455,9 @@
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(!args->is_last);
   GPR_ASSERT(args->optional_transport != NULL);
@@ -467,16 +465,17 @@
   chand->max_payload_size_for_get =
       max_payload_size_from_args(args->channel_args);
   chand->user_agent = grpc_mdelem_from_metadata_strings(
-      GRPC_MDSTR_USER_AGENT,
+      exec_ctx, GRPC_MDSTR_USER_AGENT,
       user_agent_from_args(args->channel_args,
                            args->optional_transport->vtable->name));
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {
   channel_data *chand = elem->channel_data;
-  GRPC_MDELEM_UNREF(chand->user_agent);
+  GRPC_MDELEM_UNREF(exec_ctx, chand->user_agent);
 }
 
 const grpc_channel_filter grpc_http_client_filter = {
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index b42ff06..f508231 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -38,6 +38,7 @@
 #include <string.h>
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/percent_encoding.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/transport/static_metadata.h"
 
 #define EXPECTED_CONTENT_TYPE "application/grpc"
@@ -82,31 +83,28 @@
 
 typedef struct channel_data { uint8_t unused; } channel_data;
 
-typedef struct {
-  grpc_call_element *elem;
-  grpc_exec_ctx *exec_ctx;
-} server_filter_args;
-
-static grpc_mdelem *server_filter_outgoing_metadata(void *user_data,
+static grpc_mdelem *server_filter_outgoing_metadata(grpc_exec_ctx *exec_ctx,
+                                                    void *user_data,
                                                     grpc_mdelem *md) {
   if (md->key == GRPC_MDSTR_GRPC_MESSAGE) {
     grpc_slice pct_encoded_msg = grpc_percent_encode_slice(
         md->value->slice, grpc_compatible_percent_encoding_unreserved_bytes);
     if (grpc_slice_is_equivalent(pct_encoded_msg, md->value->slice)) {
-      grpc_slice_unref(pct_encoded_msg);
+      grpc_slice_unref_internal(exec_ctx, pct_encoded_msg);
       return md;
     } else {
       return grpc_mdelem_from_metadata_strings(
-          GRPC_MDSTR_GRPC_MESSAGE, grpc_mdstr_from_slice(pct_encoded_msg));
+          exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
+          grpc_mdstr_from_slice(exec_ctx, pct_encoded_msg));
     }
   } else {
     return md;
   }
 }
 
-static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
-  server_filter_args *a = user_data;
-  grpc_call_element *elem = a->elem;
+static grpc_mdelem *server_filter(grpc_exec_ctx *exec_ctx, void *user_data,
+                                  grpc_mdelem *md) {
+  grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
 
   /* Check if it is one of the headers we care about. */
@@ -157,7 +155,7 @@
     /* swallow it and error everything out. */
     /* TODO(klempner): We ought to generate more descriptive error messages
        on the wire here. */
-    grpc_call_element_send_cancel(a->exec_ctx, elem);
+    grpc_call_element_send_cancel(exec_ctx, elem);
     return NULL;
   } else if (md->key == GRPC_MDSTR_PATH) {
     if (calld->seen_path) {
@@ -173,7 +171,7 @@
     /* translate host to :authority since :authority may be
        omitted */
     grpc_mdelem *authority = grpc_mdelem_from_metadata_strings(
-        GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
+        exec_ctx, GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
     calld->seen_authority = 1;
     return authority;
   } else if (md->key == GRPC_MDSTR_GRPC_PAYLOAD_BIN) {
@@ -181,7 +179,7 @@
        header field */
     calld->seen_payload_bin = 1;
     grpc_slice_buffer_add(&calld->read_slice_buffer,
-                          grpc_slice_ref(md->value->slice));
+                          grpc_slice_ref_internal(md->value->slice));
     grpc_slice_buffer_stream_init(&calld->read_stream,
                                   &calld->read_slice_buffer, 0);
     return NULL;
@@ -195,10 +193,8 @@
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   if (err == GRPC_ERROR_NONE) {
-    server_filter_args a;
-    a.elem = elem;
-    a.exec_ctx = exec_ctx;
-    grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, &a);
+    grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
+                               server_filter, elem);
     /* Have we seen the required http2 transport headers?
        (:method, :scheme, content-type, with :path and :authority covered
        at the channel level right now) */
@@ -310,9 +306,8 @@
   }
 
   if (op->send_trailing_metadata) {
-    server_filter_args a = {elem, exec_ctx};
-    grpc_metadata_batch_filter(op->send_trailing_metadata,
-                               server_filter_outgoing_metadata, &a);
+    grpc_metadata_batch_filter(exec_ctx, op->send_trailing_metadata,
+                               server_filter_outgoing_metadata, elem);
   }
 }
 
@@ -334,9 +329,12 @@
   call_data *calld = elem->call_data;
   /* initialize members */
   memset(calld, 0, sizeof(*calld));
-  grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
-  grpc_closure_init(&calld->hs_on_complete, hs_on_complete, elem);
-  grpc_closure_init(&calld->hs_recv_message_ready, hs_recv_message_ready, elem);
+  grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&calld->hs_on_complete, hs_on_complete, elem,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&calld->hs_recv_message_ready, hs_recv_message_ready, elem,
+                    grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&calld->read_slice_buffer);
   return GRPC_ERROR_NONE;
 }
@@ -346,14 +344,15 @@
                               const grpc_call_final_info *final_info,
                               void *ignored) {
   call_data *calld = elem->call_data;
-  grpc_slice_buffer_destroy(&calld->read_slice_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &calld->read_slice_buffer);
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   GPR_ASSERT(!args->is_last);
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel data */
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 1cf68d7..862090b 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -54,8 +54,12 @@
   return new_value;
 }
 
+static void message_size_limits_free(grpc_exec_ctx* exec_ctx, void* value) {
+  gpr_free(value);
+}
+
 static const grpc_mdstr_hash_table_vtable message_size_limits_vtable = {
-    gpr_free, message_size_limits_copy};
+    message_size_limits_free, message_size_limits_copy};
 
 static void* message_size_limits_create_from_json(const grpc_json* json) {
   int max_request_message_bytes = -1;
@@ -124,7 +128,7 @@
     gpr_free(message_string);
   }
   // Invoke the next callback.
-  grpc_exec_ctx_sched(exec_ctx, calld->next_recv_message_ready, error, NULL);
+  grpc_closure_sched(exec_ctx, calld->next_recv_message_ready, error);
 }
 
 // Start transport stream op.
@@ -160,7 +164,8 @@
   channel_data* chand = elem->channel_data;
   call_data* calld = elem->call_data;
   calld->next_recv_message_ready = NULL;
-  grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem);
+  grpc_closure_init(&calld->recv_message_ready, recv_message_ready, elem,
+                    grpc_schedule_on_exec_ctx);
   // Get max sizes from channel data, then merge in per-method config values.
   // Note: Per-method config is only available on the client, so we
   // apply the max request size to the send limit and the max response
@@ -168,8 +173,8 @@
   calld->max_send_size = chand->max_send_size;
   calld->max_recv_size = chand->max_recv_size;
   if (chand->method_limit_table != NULL) {
-    message_size_limits* limits =
-        grpc_method_config_table_get(chand->method_limit_table, args->path);
+    message_size_limits* limits = grpc_method_config_table_get(
+        exec_ctx, chand->method_limit_table, args->path);
     if (limits != NULL) {
       if (limits->max_send_size >= 0 &&
           (limits->max_send_size < calld->max_send_size ||
@@ -192,9 +197,9 @@
                               void* ignored) {}
 
 // Constructor for channel_data.
-static void init_channel_elem(grpc_exec_ctx* exec_ctx,
-                              grpc_channel_element* elem,
-                              grpc_channel_element_args* args) {
+static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
+                                     grpc_channel_element* elem,
+                                     grpc_channel_element_args* args) {
   GPR_ASSERT(!args->is_last);
   channel_data* chand = elem->channel_data;
   memset(chand, 0, sizeof(*chand));
@@ -226,18 +231,19 @@
     if (service_config != NULL) {
       chand->method_limit_table =
           grpc_service_config_create_method_config_table(
-              service_config, message_size_limits_create_from_json,
+              exec_ctx, service_config, message_size_limits_create_from_json,
               &message_size_limits_vtable);
       grpc_service_config_destroy(service_config);
     }
   }
+  return GRPC_ERROR_NONE;
 }
 
 // Destructor for channel_data.
 static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
                                  grpc_channel_element* elem) {
   channel_data* chand = elem->channel_data;
-  grpc_mdstr_hash_table_unref(chand->method_limit_table);
+  grpc_mdstr_hash_table_unref(exec_ctx, chand->method_limit_table);
 }
 
 const grpc_channel_filter grpc_message_size_filter = {
diff --git a/src/core/lib/compression/message_compress.c b/src/core/lib/compression/message_compress.c
index 6c245ac..49beb95 100644
--- a/src/core/lib/compression/message_compress.c
+++ b/src/core/lib/compression/message_compress.c
@@ -40,10 +40,12 @@
 
 #include <zlib.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 #define OUTPUT_BLOCK_SIZE 1024
 
-static int zlib_body(z_stream* zs, grpc_slice_buffer* input,
-                     grpc_slice_buffer* output,
+static int zlib_body(grpc_exec_ctx* exec_ctx, z_stream* zs,
+                     grpc_slice_buffer* input, grpc_slice_buffer* output,
                      int (*flate)(z_stream* zs, int flush)) {
   int r;
   int flush;
@@ -87,7 +89,7 @@
   return 1;
 
 error:
-  grpc_slice_unref(outbuf);
+  grpc_slice_unref_internal(exec_ctx, outbuf);
   return 0;
 }
 
@@ -97,8 +99,8 @@
 
 static void zfree_gpr(void* opaque, void* address) { gpr_free(address); }
 
-static int zlib_compress(grpc_slice_buffer* input, grpc_slice_buffer* output,
-                         int gzip) {
+static int zlib_compress(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* input,
+                         grpc_slice_buffer* output, int gzip) {
   z_stream zs;
   int r;
   size_t i;
@@ -110,10 +112,11 @@
   r = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | (gzip ? 16 : 0),
                    8, Z_DEFAULT_STRATEGY);
   GPR_ASSERT(r == Z_OK);
-  r = zlib_body(&zs, input, output, deflate) && output->length < input->length;
+  r = zlib_body(exec_ctx, &zs, input, output, deflate) &&
+      output->length < input->length;
   if (!r) {
     for (i = count_before; i < output->count; i++) {
-      grpc_slice_unref(output->slices[i]);
+      grpc_slice_unref_internal(exec_ctx, output->slices[i]);
     }
     output->count = count_before;
     output->length = length_before;
@@ -122,8 +125,8 @@
   return r;
 }
 
-static int zlib_decompress(grpc_slice_buffer* input, grpc_slice_buffer* output,
-                           int gzip) {
+static int zlib_decompress(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* input,
+                           grpc_slice_buffer* output, int gzip) {
   z_stream zs;
   int r;
   size_t i;
@@ -134,10 +137,10 @@
   zs.zfree = zfree_gpr;
   r = inflateInit2(&zs, 15 | (gzip ? 16 : 0));
   GPR_ASSERT(r == Z_OK);
-  r = zlib_body(&zs, input, output, inflate);
+  r = zlib_body(exec_ctx, &zs, input, output, inflate);
   if (!r) {
     for (i = count_before; i < output->count; i++) {
-      grpc_slice_unref(output->slices[i]);
+      grpc_slice_unref_internal(exec_ctx, output->slices[i]);
     }
     output->count = count_before;
     output->length = length_before;
@@ -149,12 +152,13 @@
 static int copy(grpc_slice_buffer* input, grpc_slice_buffer* output) {
   size_t i;
   for (i = 0; i < input->count; i++) {
-    grpc_slice_buffer_add(output, grpc_slice_ref(input->slices[i]));
+    grpc_slice_buffer_add(output, grpc_slice_ref_internal(input->slices[i]));
   }
   return 1;
 }
 
-static int compress_inner(grpc_compression_algorithm algorithm,
+static int compress_inner(grpc_exec_ctx* exec_ctx,
+                          grpc_compression_algorithm algorithm,
                           grpc_slice_buffer* input, grpc_slice_buffer* output) {
   switch (algorithm) {
     case GRPC_COMPRESS_NONE:
@@ -162,9 +166,9 @@
          rely on that here */
       return 0;
     case GRPC_COMPRESS_DEFLATE:
-      return zlib_compress(input, output, 0);
+      return zlib_compress(exec_ctx, input, output, 0);
     case GRPC_COMPRESS_GZIP:
-      return zlib_compress(input, output, 1);
+      return zlib_compress(exec_ctx, input, output, 1);
     case GRPC_COMPRESS_ALGORITHMS_COUNT:
       break;
   }
@@ -172,24 +176,26 @@
   return 0;
 }
 
-int grpc_msg_compress(grpc_compression_algorithm algorithm,
+int grpc_msg_compress(grpc_exec_ctx* exec_ctx,
+                      grpc_compression_algorithm algorithm,
                       grpc_slice_buffer* input, grpc_slice_buffer* output) {
-  if (!compress_inner(algorithm, input, output)) {
+  if (!compress_inner(exec_ctx, algorithm, input, output)) {
     copy(input, output);
     return 0;
   }
   return 1;
 }
 
-int grpc_msg_decompress(grpc_compression_algorithm algorithm,
+int grpc_msg_decompress(grpc_exec_ctx* exec_ctx,
+                        grpc_compression_algorithm algorithm,
                         grpc_slice_buffer* input, grpc_slice_buffer* output) {
   switch (algorithm) {
     case GRPC_COMPRESS_NONE:
       return copy(input, output);
     case GRPC_COMPRESS_DEFLATE:
-      return zlib_decompress(input, output, 0);
+      return zlib_decompress(exec_ctx, input, output, 0);
     case GRPC_COMPRESS_GZIP:
-      return zlib_decompress(input, output, 1);
+      return zlib_decompress(exec_ctx, input, output, 1);
     case GRPC_COMPRESS_ALGORITHMS_COUNT:
       break;
   }
diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h
index 448d36a..7bd3d98 100644
--- a/src/core/lib/compression/message_compress.h
+++ b/src/core/lib/compression/message_compress.h
@@ -40,13 +40,15 @@
 /* compress 'input' to 'output' using 'algorithm'.
    On success, appends compressed slices to output and returns 1.
    On failure, appends uncompressed slices to output and returns 0. */
-int grpc_msg_compress(grpc_compression_algorithm algorithm,
+int grpc_msg_compress(grpc_exec_ctx* exec_ctx,
+                      grpc_compression_algorithm algorithm,
                       grpc_slice_buffer* input, grpc_slice_buffer* output);
 
 /* decompress 'input' to 'output' using 'algorithm'.
    On success, appends slices to output and returns 1.
    On failure, output is unchanged, and returns 0. */
-int grpc_msg_decompress(grpc_compression_algorithm algorithm,
+int grpc_msg_decompress(grpc_exec_ctx* exec_ctx,
+                        grpc_compression_algorithm algorithm,
                         grpc_slice_buffer* input, grpc_slice_buffer* output);
 
 #endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */
diff --git a/src/core/lib/http/httpcli.c b/src/core/lib/http/httpcli.c
index fdb8aba..fb21089 100644
--- a/src/core/lib/http/httpcli.c
+++ b/src/core/lib/http/httpcli.c
@@ -47,6 +47,7 @@
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 
 typedef struct {
@@ -103,7 +104,7 @@
                    grpc_error *error) {
   grpc_polling_entity_del_from_pollset_set(exec_ctx, req->pollent,
                                            req->context->pollset_set);
-  grpc_exec_ctx_sched(exec_ctx, req->on_done, error, NULL);
+  grpc_closure_sched(exec_ctx, req->on_done, error);
   grpc_http_parser_destroy(&req->parser);
   if (req->addresses != NULL) {
     grpc_resolved_addresses_destroy(req->addresses);
@@ -111,14 +112,14 @@
   if (req->ep != NULL) {
     grpc_endpoint_destroy(exec_ctx, req->ep);
   }
-  grpc_slice_unref(req->request_text);
+  grpc_slice_unref_internal(exec_ctx, req->request_text);
   gpr_free(req->host);
   gpr_free(req->ssl_host_override);
   grpc_iomgr_unregister_object(&req->iomgr_obj);
-  grpc_slice_buffer_destroy(&req->incoming);
-  grpc_slice_buffer_destroy(&req->outgoing);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &req->incoming);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &req->outgoing);
   GRPC_ERROR_UNREF(req->overall_error);
-  grpc_resource_quota_internal_unref(exec_ctx, req->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, req->resource_quota);
   gpr_free(req);
 }
 
@@ -178,7 +179,7 @@
 }
 
 static void start_write(grpc_exec_ctx *exec_ctx, internal_request *req) {
-  grpc_slice_ref(req->request_text);
+  grpc_slice_ref_internal(req->request_text);
   grpc_slice_buffer_add(&req->outgoing, req->request_text);
   grpc_endpoint_write(exec_ctx, req->ep, &req->outgoing, &req->done_write);
 }
@@ -224,7 +225,8 @@
     return;
   }
   addr = &req->addresses->addrs[req->next_address++];
-  grpc_closure_init(&req->connected, on_connected, req);
+  grpc_closure_init(&req->connected, on_connected, req,
+                    grpc_schedule_on_exec_ctx);
   grpc_arg arg;
   arg.key = GRPC_ARG_RESOURCE_QUOTA;
   arg.type = GRPC_ARG_POINTER;
@@ -265,9 +267,10 @@
   req->context = context;
   req->pollent = pollent;
   req->overall_error = GRPC_ERROR_NONE;
-  req->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
-  grpc_closure_init(&req->on_read, on_read, req);
-  grpc_closure_init(&req->done_write, done_write, req);
+  req->resource_quota = grpc_resource_quota_ref_internal(resource_quota);
+  grpc_closure_init(&req->on_read, on_read, req, grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&req->done_write, done_write, req,
+                    grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&req->incoming);
   grpc_slice_buffer_init(&req->outgoing);
   grpc_iomgr_register_object(&req->iomgr_obj, name);
@@ -277,8 +280,11 @@
   GPR_ASSERT(pollent);
   grpc_polling_entity_add_to_pollset_set(exec_ctx, req->pollent,
                                          req->context->pollset_set);
-  grpc_resolve_address(exec_ctx, request->host, req->handshaker->default_port,
-                       grpc_closure_create(on_resolved, req), &req->addresses);
+  grpc_resolve_address(
+      exec_ctx, request->host, req->handshaker->default_port,
+      req->context->pollset_set,
+      grpc_closure_create(on_resolved, req, grpc_schedule_on_exec_ctx),
+      &req->addresses);
 }
 
 void grpc_httpcli_get(grpc_exec_ctx *exec_ctx, grpc_httpcli_context *context,
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 14cdb1d..440817c 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -41,6 +41,7 @@
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/security/transport/security_handshaker.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/tsi/ssl_transport_security.h"
 
@@ -50,7 +51,8 @@
   char *secure_peer_name;
 } grpc_httpcli_ssl_channel_security_connector;
 
-static void httpcli_ssl_destroy(grpc_security_connector *sc) {
+static void httpcli_ssl_destroy(grpc_exec_ctx *exec_ctx,
+                                grpc_security_connector *sc) {
   grpc_httpcli_ssl_channel_security_connector *c =
       (grpc_httpcli_ssl_channel_security_connector *)sc;
   if (c->handshaker_factory != NULL) {
@@ -96,7 +98,7 @@
     error = GRPC_ERROR_CREATE(msg);
     gpr_free(msg);
   }
-  grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
+  grpc_closure_sched(exec_ctx, on_peer_checked, error);
   tsi_peer_destruct(&peer);
 }
 
@@ -104,8 +106,9 @@
     httpcli_ssl_destroy, httpcli_ssl_check_peer};
 
 static grpc_security_status httpcli_ssl_channel_security_connector_create(
-    const unsigned char *pem_root_certs, size_t pem_root_certs_size,
-    const char *secure_peer_name, grpc_channel_security_connector **sc) {
+    grpc_exec_ctx *exec_ctx, const unsigned char *pem_root_certs,
+    size_t pem_root_certs_size, const char *secure_peer_name,
+    grpc_channel_security_connector **sc) {
   tsi_result result = TSI_OK;
   grpc_httpcli_ssl_channel_security_connector *c;
 
@@ -129,7 +132,7 @@
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
-    httpcli_ssl_destroy(&c->base.base);
+    httpcli_ssl_destroy(exec_ctx, &c->base.base);
     *sc = NULL;
     return GRPC_SECURITY_ERROR;
   }
@@ -156,8 +159,8 @@
     grpc_error_free_string(msg);
     c->func(exec_ctx, c->arg, NULL);
   } else {
-    grpc_channel_args_destroy(args->args);
-    grpc_slice_buffer_destroy(args->read_buffer);
+    grpc_channel_args_destroy(exec_ctx, args->args);
+    grpc_slice_buffer_destroy_internal(exec_ctx, args->read_buffer);
     gpr_free(args->read_buffer);
     c->func(exec_ctx, c->arg, args->endpoint);
   }
@@ -184,14 +187,14 @@
   c->arg = arg;
   c->handshake_mgr = grpc_handshake_manager_create();
   GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
-                 pem_root_certs, pem_root_certs_size, host, &sc) ==
+                 exec_ctx, pem_root_certs, pem_root_certs_size, host, &sc) ==
              GRPC_SECURITY_OK);
   grpc_channel_security_connector_add_handshakers(exec_ctx, sc,
                                                   c->handshake_mgr);
   grpc_handshake_manager_do_handshake(
       exec_ctx, c->handshake_mgr, tcp, NULL /* channel_args */, deadline,
       NULL /* acceptor */, on_handshake_done, c /* user_data */);
-  GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
+  GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &sc->base, "httpcli");
 }
 
 const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake};
diff --git a/src/core/lib/iomgr/README.md b/src/core/lib/iomgr/README.md
new file mode 100644
index 0000000..9b22b76
--- /dev/null
+++ b/src/core/lib/iomgr/README.md
@@ -0,0 +1,6 @@
+# iomgr
+
+Platform abstractions for I/O (mostly network).
+
+Provides abstractions over TCP/UDP I/O, file loading, polling, and concurrency
+management for various operating systems.
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
index c6ddc76..da0ec87 100644
--- a/src/core/lib/iomgr/closure.c
+++ b/src/core/lib/iomgr/closure.c
@@ -37,10 +37,13 @@
 
 #include "src/core/lib/profiling/timers.h"
 
-void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
-                       void *cb_arg) {
+grpc_closure *grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
+                                void *cb_arg,
+                                grpc_closure_scheduler *scheduler) {
   closure->cb = cb;
   closure->cb_arg = cb_arg;
+  closure->scheduler = scheduler;
+  return closure;
 }
 
 void grpc_closure_list_init(grpc_closure_list *closure_list) {
@@ -105,11 +108,12 @@
   cb(exec_ctx, cb_arg, error);
 }
 
-grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg) {
+grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg,
+                                  grpc_closure_scheduler *scheduler) {
   wrapped_closure *wc = gpr_malloc(sizeof(*wc));
   wc->cb = cb;
   wc->cb_arg = cb_arg;
-  grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
+  grpc_closure_init(&wc->wrapper, closure_wrapper, wc, scheduler);
   return &wc->wrapper;
 }
 
@@ -117,8 +121,30 @@
                       grpc_error *error) {
   GPR_TIMER_BEGIN("grpc_closure_run", 0);
   if (c != NULL) {
-    c->cb(exec_ctx, c->cb_arg, error);
+    c->scheduler->vtable->run(exec_ctx, c, error);
+  } else {
+    GRPC_ERROR_UNREF(error);
   }
-  GRPC_ERROR_UNREF(error);
   GPR_TIMER_END("grpc_closure_run", 0);
 }
+
+void grpc_closure_sched(grpc_exec_ctx *exec_ctx, grpc_closure *c,
+                        grpc_error *error) {
+  GPR_TIMER_BEGIN("grpc_closure_sched", 0);
+  if (c != NULL) {
+    c->scheduler->vtable->sched(exec_ctx, c, error);
+  } else {
+    GRPC_ERROR_UNREF(error);
+  }
+  GPR_TIMER_END("grpc_closure_sched", 0);
+}
+
+void grpc_closure_list_sched(grpc_exec_ctx *exec_ctx, grpc_closure_list *list) {
+  grpc_closure *c = list->head;
+  while (c != NULL) {
+    grpc_closure *next = c->next_data.next;
+    c->scheduler->vtable->sched(exec_ctx, c, c->error_data.error);
+    c = next;
+  }
+  list->head = list->tail = NULL;
+}
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index 2b4b271..ee386fb 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -35,6 +35,8 @@
 #define GRPC_CORE_LIB_IOMGR_CLOSURE_H
 
 #include <grpc/support/port_platform.h>
+
+#include <grpc/impl/codegen/exec_ctx_fwd.h>
 #include <stdbool.h>
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/support/mpscq.h"
@@ -42,10 +44,6 @@
 struct grpc_closure;
 typedef struct grpc_closure grpc_closure;
 
-/* forward declaration for exec_ctx.h */
-struct grpc_exec_ctx;
-typedef struct grpc_exec_ctx grpc_exec_ctx;
-
 typedef struct grpc_closure_list {
   grpc_closure *head;
   grpc_closure *tail;
@@ -59,6 +57,22 @@
 typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
                                    grpc_error *error);
 
+typedef struct grpc_closure_scheduler grpc_closure_scheduler;
+
+typedef struct grpc_closure_scheduler_vtable {
+  /* NOTE: for all these functions, closure->scheduler == the scheduler that was
+           used to find this vtable */
+  void (*run)(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+              grpc_error *error);
+  void (*sched)(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                grpc_error *error);
+} grpc_closure_scheduler_vtable;
+
+/** Abstract type that can schedule closures for execution */
+struct grpc_closure_scheduler {
+  const grpc_closure_scheduler_vtable *vtable;
+};
+
 /** A closure over a grpc_iomgr_cb_func. */
 struct grpc_closure {
   /** Once queued, next indicates the next queued closure; before then, scratch
@@ -75,6 +89,10 @@
   /** Arguments to be passed to "cb". */
   void *cb_arg;
 
+  /** Scheduler to schedule against: NULL to schedule against current execution
+      context */
+  grpc_closure_scheduler *scheduler;
+
   /** Once queued, the result of the closure. Before then: scratch space */
   union {
     grpc_error *error;
@@ -82,12 +100,14 @@
   } error_data;
 };
 
-/** Initializes \a closure with \a cb and \a cb_arg. */
-void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
-                       void *cb_arg);
+/** Initializes \a closure with \a cb and \a cb_arg. Returns \a closure. */
+grpc_closure *grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
+                                void *cb_arg,
+                                grpc_closure_scheduler *scheduler);
 
 /* Create a heap allocated closure: try to avoid except for very rare events */
-grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg);
+grpc_closure *grpc_closure_create(grpc_iomgr_cb_func cb, void *cb_arg,
+                                  grpc_closure_scheduler *scheduler);
 
 #define GRPC_CLOSURE_LIST_INIT \
   { NULL, NULL }
@@ -115,4 +135,13 @@
 void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
                       grpc_error *error);
 
+/** Schedule a closure to be run. Does not need to be run from a safe point. */
+void grpc_closure_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                        grpc_error *error);
+
+/** Schedule all closures in a list to be run. Does not need to be run from a
+ * safe point. */
+void grpc_closure_list_sched(grpc_exec_ctx *exec_ctx,
+                             grpc_closure_list *closure_list);
+
 #endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */
diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c
index cfc6702..c26a73b 100644
--- a/src/core/lib/iomgr/combiner.c
+++ b/src/core/lib/iomgr/combiner.c
@@ -56,6 +56,10 @@
 struct grpc_combiner {
   grpc_combiner *next_combiner_on_this_exec_ctx;
   grpc_workqueue *optional_workqueue;
+  grpc_closure_scheduler uncovered_scheduler;
+  grpc_closure_scheduler covered_scheduler;
+  grpc_closure_scheduler uncovered_finally_scheduler;
+  grpc_closure_scheduler covered_finally_scheduler;
   gpr_mpscq queue;
   // state is:
   // lower bit - zero if orphaned (STATE_UNORPHANED)
@@ -70,6 +74,26 @@
   grpc_closure offload;
 };
 
+static void combiner_exec_uncovered(grpc_exec_ctx *exec_ctx,
+                                    grpc_closure *closure, grpc_error *error);
+static void combiner_exec_covered(grpc_exec_ctx *exec_ctx,
+                                  grpc_closure *closure, grpc_error *error);
+static void combiner_finally_exec_uncovered(grpc_exec_ctx *exec_ctx,
+                                            grpc_closure *closure,
+                                            grpc_error *error);
+static void combiner_finally_exec_covered(grpc_exec_ctx *exec_ctx,
+                                          grpc_closure *closure,
+                                          grpc_error *error);
+
+static const grpc_closure_scheduler_vtable scheduler_uncovered = {
+    combiner_exec_uncovered, combiner_exec_uncovered};
+static const grpc_closure_scheduler_vtable scheduler_covered = {
+    combiner_exec_covered, combiner_exec_covered};
+static const grpc_closure_scheduler_vtable finally_scheduler_uncovered = {
+    combiner_finally_exec_uncovered, combiner_finally_exec_uncovered};
+static const grpc_closure_scheduler_vtable finally_scheduler_covered = {
+    combiner_finally_exec_covered, combiner_finally_exec_covered};
+
 static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
 
 typedef struct {
@@ -102,11 +126,16 @@
   lock->time_to_execute_final_list = false;
   lock->optional_workqueue = optional_workqueue;
   lock->final_list_covered_by_poller = false;
+  lock->uncovered_scheduler.vtable = &scheduler_uncovered;
+  lock->covered_scheduler.vtable = &scheduler_covered;
+  lock->uncovered_finally_scheduler.vtable = &finally_scheduler_uncovered;
+  lock->covered_finally_scheduler.vtable = &finally_scheduler_covered;
   gpr_atm_no_barrier_store(&lock->state, STATE_UNORPHANED);
   gpr_atm_no_barrier_store(&lock->elements_covered_by_poller, 0);
   gpr_mpscq_init(&lock->queue);
   grpc_closure_list_init(&lock->final_list);
-  grpc_closure_init(&lock->offload, offload, lock);
+  grpc_closure_init(&lock->offload, offload, lock,
+                    grpc_workqueue_scheduler(lock->optional_workqueue));
   GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock));
   return lock;
 }
@@ -148,9 +177,9 @@
   }
 }
 
-void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
-                           grpc_closure *cl, grpc_error *error,
-                           bool covered_by_poller) {
+static void combiner_exec(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+                          grpc_closure *cl, grpc_error *error,
+                          bool covered_by_poller) {
   GPR_TIMER_BEGIN("combiner.execute", 0);
   gpr_atm last = gpr_atm_full_fetch_add(&lock->state, STATE_ELEM_COUNT_LOW_BIT);
   GRPC_COMBINER_TRACE(gpr_log(
@@ -171,6 +200,24 @@
   GPR_TIMER_END("combiner.execute", 0);
 }
 
+#define COMBINER_FROM_CLOSURE_SCHEDULER(closure, scheduler_name) \
+  ((grpc_combiner *)(((char *)((closure)->scheduler)) -          \
+                     offsetof(grpc_combiner, scheduler_name)))
+
+static void combiner_exec_uncovered(grpc_exec_ctx *exec_ctx, grpc_closure *cl,
+                                    grpc_error *error) {
+  combiner_exec(exec_ctx,
+                COMBINER_FROM_CLOSURE_SCHEDULER(cl, uncovered_scheduler), cl,
+                error, false);
+}
+
+static void combiner_exec_covered(grpc_exec_ctx *exec_ctx, grpc_closure *cl,
+                                  grpc_error *error) {
+  combiner_exec(exec_ctx,
+                COMBINER_FROM_CLOSURE_SCHEDULER(cl, covered_scheduler), cl,
+                error, true);
+}
+
 static void move_next(grpc_exec_ctx *exec_ctx) {
   exec_ctx->active_combiner =
       exec_ctx->active_combiner->next_combiner_on_this_exec_ctx;
@@ -188,8 +235,7 @@
   move_next(exec_ctx);
   GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p queue_offload --> %p", lock,
                               lock->optional_workqueue));
-  grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, &lock->offload,
-                         GRPC_ERROR_NONE);
+  grpc_closure_sched(exec_ctx, &lock->offload, GRPC_ERROR_NONE);
 }
 
 bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) {
@@ -312,23 +358,22 @@
 }
 
 static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure,
-                            grpc_error *error) {
-  grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure,
-                                GRPC_ERROR_REF(error), false);
-}
+                            grpc_error *error);
 
-void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
-                                   grpc_closure *closure, grpc_error *error,
-                                   bool covered_by_poller) {
+static void combiner_execute_finally(grpc_exec_ctx *exec_ctx,
+                                     grpc_combiner *lock, grpc_closure *closure,
+                                     grpc_error *error,
+                                     bool covered_by_poller) {
   GRPC_COMBINER_TRACE(gpr_log(
       GPR_DEBUG, "C:%p grpc_combiner_execute_finally c=%p; ac=%p; cov=%d", lock,
       closure, exec_ctx->active_combiner, covered_by_poller));
   GPR_TIMER_BEGIN("combiner.execute_finally", 0);
   if (exec_ctx->active_combiner != lock) {
     GPR_TIMER_MARK("slowpath", 0);
-    grpc_combiner_execute(exec_ctx, lock,
-                          grpc_closure_create(enqueue_finally, closure), error,
-                          false);
+    grpc_closure_sched(
+        exec_ctx, grpc_closure_create(enqueue_finally, closure,
+                                      grpc_combiner_scheduler(lock, false)),
+        error);
     GPR_TIMER_END("combiner.execute_finally", 0);
     return;
   }
@@ -342,3 +387,36 @@
   grpc_closure_list_append(&lock->final_list, closure, error);
   GPR_TIMER_END("combiner.execute_finally", 0);
 }
+
+static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure,
+                            grpc_error *error) {
+  combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure,
+                           GRPC_ERROR_REF(error), false);
+}
+
+static void combiner_finally_exec_uncovered(grpc_exec_ctx *exec_ctx,
+                                            grpc_closure *cl,
+                                            grpc_error *error) {
+  combiner_execute_finally(exec_ctx, COMBINER_FROM_CLOSURE_SCHEDULER(
+                                         cl, uncovered_finally_scheduler),
+                           cl, error, false);
+}
+
+static void combiner_finally_exec_covered(grpc_exec_ctx *exec_ctx,
+                                          grpc_closure *cl, grpc_error *error) {
+  combiner_execute_finally(
+      exec_ctx, COMBINER_FROM_CLOSURE_SCHEDULER(cl, covered_finally_scheduler),
+      cl, error, true);
+}
+
+grpc_closure_scheduler *grpc_combiner_scheduler(grpc_combiner *combiner,
+                                                bool covered_by_poller) {
+  return covered_by_poller ? &combiner->covered_scheduler
+                           : &combiner->uncovered_scheduler;
+}
+
+grpc_closure_scheduler *grpc_combiner_finally_scheduler(
+    grpc_combiner *combiner, bool covered_by_poller) {
+  return covered_by_poller ? &combiner->covered_finally_scheduler
+                           : &combiner->uncovered_finally_scheduler;
+}
diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h
index d04eeed..81dff85 100644
--- a/src/core/lib/iomgr/combiner.h
+++ b/src/core/lib/iomgr/combiner.h
@@ -50,14 +50,12 @@
 grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue);
 // Destroy the lock
 void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock);
-// Execute \a action within the lock.
-void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
-                           grpc_closure *closure, grpc_error *error,
-                           bool covered_by_poller);
-// Execute \a action within the lock just prior to unlocking.
-void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
-                                   grpc_closure *closure, grpc_error *error,
-                                   bool covered_by_poller);
+// Fetch a scheduler to schedule closures against
+grpc_closure_scheduler *grpc_combiner_scheduler(grpc_combiner *lock,
+                                                bool covered_by_poller);
+// Scheduler to execute \a action within the lock just prior to unlocking.
+grpc_closure_scheduler *grpc_combiner_finally_scheduler(grpc_combiner *lock,
+                                                        bool covered_by_poller);
 
 bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx);
 
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 1b15e0e..d6664ae 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -31,7 +31,6 @@
  *
  */
 
-#include <grpc/grpc_posix.h>
 #include "src/core/lib/iomgr/port.h"
 
 /* This polling engine is only relevant on linux kernels supporting epoll() */
@@ -202,6 +201,8 @@
 
 /* This is also used as grpc_workqueue (by directly casing it) */
 typedef struct polling_island {
+  grpc_closure_scheduler workqueue_scheduler;
+
   gpr_mu mu;
   /* Ref count. Use PI_ADD_REF() and PI_UNREF() macros to increment/decrement
      the refcount.
@@ -305,6 +306,8 @@
 
 /* Forward declaration */
 static void polling_island_delete(grpc_exec_ctx *exec_ctx, polling_island *pi);
+static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                              grpc_error *error);
 
 #ifdef GRPC_TSAN
 /* Currently TSAN may incorrectly flag data races between epoll_ctl and
@@ -317,6 +320,9 @@
 gpr_atm g_epoll_sync;
 #endif /* defined(GRPC_TSAN) */
 
+static const grpc_closure_scheduler_vtable workqueue_scheduler_vtable = {
+    workqueue_enqueue, workqueue_enqueue};
+
 static void pi_add_ref(polling_island *pi);
 static void pi_unref(grpc_exec_ctx *exec_ctx, polling_island *pi);
 
@@ -529,6 +535,7 @@
   *error = GRPC_ERROR_NONE;
 
   pi = gpr_malloc(sizeof(*pi));
+  pi->workqueue_scheduler.vtable = &workqueue_scheduler_vtable;
   gpr_mu_init(&pi->mu);
   pi->fd_cnt = 0;
   pi->fd_capacity = 0;
@@ -800,10 +807,10 @@
   return q;
 }
 
-static void workqueue_enqueue(grpc_exec_ctx *exec_ctx,
-                              grpc_workqueue *workqueue, grpc_closure *closure,
+static void workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
                               grpc_error *error) {
   GPR_TIMER_BEGIN("workqueue.enqueue", 0);
+  grpc_workqueue *workqueue = (grpc_workqueue *)closure->scheduler;
   /* take a ref to the workqueue: otherwise it can happen that whatever events
    * this kicks off ends up destroying the workqueue before this function
    * completes */
@@ -820,6 +827,12 @@
   GPR_TIMER_END("workqueue.enqueue", 0);
 }
 
+static grpc_closure_scheduler *workqueue_scheduler(grpc_workqueue *workqueue) {
+  polling_island *pi = (polling_island *)workqueue;
+  return workqueue == NULL ? grpc_schedule_on_exec_ctx
+                           : &pi->workqueue_scheduler;
+}
+
 static grpc_error *polling_island_global_init() {
   grpc_error *error = GRPC_ERROR_NONE;
 
@@ -1030,8 +1043,7 @@
     fd->po.pi = NULL;
   }
 
-  grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error),
-                      NULL);
+  grpc_closure_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error));
 
   gpr_mu_unlock(&fd->po.mu);
   UNREF_BY(fd, 2, reason); /* Drop the reference */
@@ -1057,16 +1069,14 @@
 static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
                              grpc_closure **st, grpc_closure *closure) {
   if (fd->shutdown) {
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"));
   } else if (*st == CLOSURE_NOT_READY) {
     /* not ready ==> switch to a waiting state by setting the closure */
     *st = closure;
   } else if (*st == CLOSURE_READY) {
     /* already ready ==> queue the closure to run immediately */
     *st = CLOSURE_NOT_READY;
-    grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
-                        NULL);
+    grpc_closure_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown));
   } else {
     /* upcallptr was set to a different closure.  This is an error! */
     gpr_log(GPR_ERROR,
@@ -1088,7 +1098,7 @@
     return 0;
   } else {
     /* waiting ==> queue closure */
-    grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
+    grpc_closure_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown));
     *st = CLOSURE_NOT_READY;
     return 1;
   }
@@ -1359,7 +1369,7 @@
 
   /* Release the ref and set pollset->po.pi to NULL */
   pollset_release_polling_island(exec_ctx, pollset, "ps_shutdown");
-  grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE);
 }
 
 /* pollset->po.mu lock must be held by the caller before calling this */
@@ -1410,7 +1420,9 @@
         workqueue_maybe_wakeup(pi);
       }
       grpc_closure *c = (grpc_closure *)n;
-      grpc_closure_run(exec_ctx, c, c->error_data.error);
+      grpc_error *error = c->error_data.error;
+      c->cb(exec_ctx, c->cb_arg, error);
+      GRPC_ERROR_UNREF(error);
       return true;
     } else if (gpr_atm_no_barrier_load(&pi->workqueue_item_count) > 0) {
       /* n == NULL might mean there's work but it's not available to be popped
@@ -1959,7 +1971,7 @@
 
     .workqueue_ref = workqueue_ref,
     .workqueue_unref = workqueue_unref,
-    .workqueue_enqueue = workqueue_enqueue,
+    .workqueue_scheduler = workqueue_scheduler,
 
     .shutdown_engine = shutdown_engine,
 };
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index 486181d..9477ac3 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -397,7 +397,7 @@
   if (!fd->released) {
     close(fd->fd);
   }
-  grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_NONE);
 }
 
 static int fd_wrapped_fd(grpc_fd *fd) {
@@ -455,16 +455,14 @@
 static void notify_on_locked(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
                              grpc_closure **st, grpc_closure *closure) {
   if (fd->shutdown) {
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CREATE("FD shutdown"));
   } else if (*st == CLOSURE_NOT_READY) {
     /* not ready ==> switch to a waiting state by setting the closure */
     *st = closure;
   } else if (*st == CLOSURE_READY) {
     /* already ready ==> queue the closure to run immediately */
     *st = CLOSURE_NOT_READY;
-    grpc_exec_ctx_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown),
-                        NULL);
+    grpc_closure_sched(exec_ctx, closure, fd_shutdown_error(fd->shutdown));
     maybe_wake_one_watcher_locked(fd);
   } else {
     /* upcallptr was set to a different closure.  This is an error! */
@@ -487,7 +485,7 @@
     return 0;
   } else {
     /* waiting ==> queue closure */
-    grpc_exec_ctx_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown), NULL);
+    grpc_closure_sched(exec_ctx, *st, fd_shutdown_error(fd->shutdown));
     *st = CLOSURE_NOT_READY;
     return 1;
   }
@@ -850,7 +848,7 @@
     GRPC_FD_UNREF(pollset->fds[i], "multipoller");
   }
   pollset->fd_count = 0;
-  grpc_exec_ctx_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, pollset->shutdown_done, GRPC_ERROR_NONE);
 }
 
 static void work_combine_error(grpc_error **composite, grpc_error *error) {
@@ -899,7 +897,7 @@
   if (!pollset_has_workers(pollset) &&
       !grpc_closure_list_empty(pollset->idle_jobs)) {
     GPR_TIMER_MARK("pollset_work.idle_jobs", 0);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
+    grpc_closure_list_sched(exec_ctx, &pollset->idle_jobs);
     goto done;
   }
   /* If we're shutting down then we don't execute any extended work */
@@ -1079,7 +1077,7 @@
        * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
       gpr_mu_lock(&pollset->mu);
     } else if (!grpc_closure_list_empty(pollset->idle_jobs)) {
-      grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
+      grpc_closure_list_sched(exec_ctx, &pollset->idle_jobs);
       gpr_mu_unlock(&pollset->mu);
       grpc_exec_ctx_flush(exec_ctx);
       gpr_mu_lock(&pollset->mu);
@@ -1098,7 +1096,7 @@
   pollset->shutdown_done = closure;
   pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
   if (!pollset_has_workers(pollset)) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
+    grpc_closure_list_sched(exec_ctx, &pollset->idle_jobs);
   }
   if (!pollset->called_shutdown && !pollset_has_workers(pollset)) {
     pollset->called_shutdown = 1;
@@ -1286,10 +1284,8 @@
                             grpc_workqueue *workqueue) {}
 #endif
 
-static void workqueue_enqueue(grpc_exec_ctx *exec_ctx,
-                              grpc_workqueue *workqueue, grpc_closure *closure,
-                              grpc_error *error) {
-  grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+static grpc_closure_scheduler *workqueue_scheduler(grpc_workqueue *workqueue) {
+  return grpc_schedule_on_exec_ctx;
 }
 
 /*******************************************************************************
@@ -1532,7 +1528,7 @@
 
     .workqueue_ref = workqueue_ref,
     .workqueue_unref = workqueue_unref,
-    .workqueue_enqueue = workqueue_enqueue,
+    .workqueue_scheduler = workqueue_scheduler,
 
     .shutdown_engine = shutdown_engine,
 };
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index ab13989..2975d61 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -275,9 +275,8 @@
 }
 #endif
 
-void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                            grpc_closure *closure, grpc_error *error) {
-  g_event_engine->workqueue_enqueue(exec_ctx, workqueue, closure, error);
+grpc_closure_scheduler *grpc_workqueue_scheduler(grpc_workqueue *workqueue) {
+  return g_event_engine->workqueue_scheduler(workqueue);
 }
 
 #endif  // GRPC_POSIX_SOCKET
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index cb58325..1068a4b 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -106,8 +106,7 @@
   grpc_workqueue *(*workqueue_ref)(grpc_workqueue *workqueue);
   void (*workqueue_unref)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
 #endif
-  void (*workqueue_enqueue)(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                            grpc_closure *closure, grpc_error *error);
+  grpc_closure_scheduler *(*workqueue_scheduler)(grpc_workqueue *workqueue);
 } grpc_event_engine_vtable;
 
 void grpc_event_engine_init(void);
diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c
index 604713e..6aa788f 100644
--- a/src/core/lib/iomgr/exec_ctx.c
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -57,7 +57,6 @@
   return true;
 }
 
-#ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
 bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
   bool did_something = 0;
   GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
@@ -67,8 +66,10 @@
       exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
       while (c != NULL) {
         grpc_closure *next = c->next_data.next;
+        grpc_error *error = c->error_data.error;
         did_something = true;
-        grpc_closure_run(exec_ctx, c, c->error_data.error);
+        c->cb(exec_ctx, c->cb_arg, error);
+        GRPC_ERROR_UNREF(error);
         c = next;
       }
     } else if (!grpc_combiner_continue_exec_ctx(exec_ctx)) {
@@ -76,30 +77,6 @@
     }
   }
   GPR_ASSERT(exec_ctx->active_combiner == NULL);
-  if (exec_ctx->stealing_from_workqueue != NULL) {
-    if (grpc_exec_ctx_ready_to_finish(exec_ctx)) {
-      grpc_workqueue_enqueue(exec_ctx, exec_ctx->stealing_from_workqueue,
-                             exec_ctx->stolen_closure,
-                             exec_ctx->stolen_closure->error_data.error);
-      GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue,
-                           "exec_ctx_sched");
-      exec_ctx->stealing_from_workqueue = NULL;
-      exec_ctx->stolen_closure = NULL;
-    } else {
-      grpc_closure *c = exec_ctx->stolen_closure;
-      GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue,
-                           "exec_ctx_sched");
-      exec_ctx->stealing_from_workqueue = NULL;
-      exec_ctx->stolen_closure = NULL;
-      grpc_error *error = c->error_data.error;
-      GPR_TIMER_BEGIN("grpc_exec_ctx_flush.stolen_cb", 0);
-      c->cb(exec_ctx, c->cb_arg, error);
-      GRPC_ERROR_UNREF(error);
-      GPR_TIMER_END("grpc_exec_ctx_flush.stolen_cb", 0);
-      grpc_exec_ctx_flush(exec_ctx);
-      did_something = true;
-    }
-  }
   GPR_TIMER_END("grpc_exec_ctx_flush", 0);
   return did_something;
 }
@@ -109,104 +86,21 @@
   grpc_exec_ctx_flush(exec_ctx);
 }
 
-void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                         grpc_error *error,
-                         grpc_workqueue *offload_target_or_null) {
-  GPR_TIMER_BEGIN("grpc_exec_ctx_sched", 0);
-  if (offload_target_or_null == NULL) {
-    grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
-  } else if (exec_ctx->stealing_from_workqueue == NULL) {
-    exec_ctx->stealing_from_workqueue = offload_target_or_null;
-    closure->error_data.error = error;
-    exec_ctx->stolen_closure = closure;
-  } else if (exec_ctx->stealing_from_workqueue != offload_target_or_null) {
-    grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, closure, error);
-    GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched");
-  } else { /* stealing_from_workqueue == offload_target_or_null */
-    grpc_workqueue_enqueue(exec_ctx, offload_target_or_null,
-                           exec_ctx->stolen_closure,
-                           exec_ctx->stolen_closure->error_data.error);
-    closure->error_data.error = error;
-    exec_ctx->stolen_closure = closure;
-    GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched");
-  }
-  GPR_TIMER_END("grpc_exec_ctx_sched", 0);
+static void exec_ctx_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                         grpc_error *error) {
+  closure->cb(exec_ctx, closure->cb_arg, error);
+  GRPC_ERROR_UNREF(error);
 }
 
-void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list,
-                                grpc_workqueue *offload_target_or_null) {
-  grpc_closure_list_move(list, &exec_ctx->closure_list);
+static void exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                           grpc_error *error) {
+  grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
 }
 
 void grpc_exec_ctx_global_init(void) {}
 void grpc_exec_ctx_global_shutdown(void) {}
-#else
-static gpr_mu g_mu;
-static gpr_cv g_cv;
-static int g_threads = 0;
 
-static void run_closure(void *arg) {
-  grpc_closure *closure = arg;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  closure->cb(&exec_ctx, closure->cb_arg, (closure->final_data & 1) != 0);
-  grpc_exec_ctx_finish(&exec_ctx);
-  gpr_mu_lock(&g_mu);
-  if (--g_threads == 0) {
-    gpr_cv_signal(&g_cv);
-  }
-  gpr_mu_unlock(&g_mu);
-}
-
-static void start_closure(grpc_closure *closure) {
-  gpr_thd_id id;
-  gpr_mu_lock(&g_mu);
-  g_threads++;
-  gpr_mu_unlock(&g_mu);
-  gpr_thd_new(&id, run_closure, closure, NULL);
-}
-
-bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) { return false; }
-
-void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx) {}
-
-void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                           bool success,
-                           grpc_workqueue *offload_target_or_null) {
-  GPR_ASSERT(offload_target_or_null == NULL);
-  if (closure == NULL) return;
-  closure->final_data = success;
-  start_closure(closure);
-}
-
-void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list,
-                                grpc_workqueue *offload_target_or_null) {
-  GPR_ASSERT(offload_target_or_null == NULL);
-  if (list == NULL) return;
-  grpc_closure *p = list->head;
-  while (p) {
-    grpc_closure *start = p;
-    p = grpc_closure_next(start);
-    start_closure(start);
-  }
-  grpc_closure_list r = GRPC_CLOSURE_LIST_INIT;
-  *list = r;
-}
-
-void grpc_exec_ctx_global_init(void) {
-  gpr_mu_init(&g_mu);
-  gpr_cv_init(&g_cv);
-}
-
-void grpc_exec_ctx_global_shutdown(void) {
-  gpr_mu_lock(&g_mu);
-  while (g_threads != 0) {
-    gpr_cv_wait(&g_cv, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
-  }
-  gpr_mu_unlock(&g_mu);
-
-  gpr_mu_destroy(&g_mu);
-  gpr_cv_destroy(&g_cv);
-}
-#endif
+static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = {
+    exec_ctx_run, exec_ctx_sched};
+static grpc_closure_scheduler exec_ctx_scheduler = {&exec_ctx_scheduler_vtable};
+grpc_closure_scheduler *grpc_schedule_on_exec_ctx = &exec_ctx_scheduler;
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index 7e50cb9..e566f1b 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -66,17 +66,6 @@
 #ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
 struct grpc_exec_ctx {
   grpc_closure_list closure_list;
-  /** The workqueue we're stealing work from.
-      As items are queued to the execution context, we try to steal one
-      workqueue item and execute it inline (assuming the exec_ctx is not
-      finished) - doing so does not invalidate the workqueue's contract, and
-      provides a small latency win in cases where we get a hit */
-  grpc_workqueue *stealing_from_workqueue;
-  /** The workqueue item that was stolen from the workqueue above. When new
-      items are scheduled to be offloaded to that workqueue, we need to update
-      this like a 1-deep fifo to maintain the invariant that workqueue items
-      queued by one thread are started in order */
-  grpc_closure *stolen_closure;
   /** currently active combiner: updated only via combiner.c */
   grpc_combiner *active_combiner;
   /** last active combiner in the active combiner list */
@@ -89,10 +78,7 @@
 /* initializer for grpc_exec_ctx:
    prefer to use GRPC_EXEC_CTX_INIT whenever possible */
 #define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \
-  {                                                                          \
-    GRPC_CLOSURE_LIST_INIT, NULL, NULL, NULL, NULL, false, finish_check_arg, \
-        finish_check                                                         \
-  }
+  { GRPC_CLOSURE_LIST_INIT, NULL, NULL, false, finish_check_arg, finish_check }
 #else
 struct grpc_exec_ctx {
   bool cached_ready_to_finish;
@@ -108,6 +94,8 @@
 #define GRPC_EXEC_CTX_INIT \
   GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_always_ready_to_finish, NULL)
 
+extern grpc_closure_scheduler *grpc_schedule_on_exec_ctx;
+
 /** Flush any work that has been enqueued onto this grpc_exec_ctx.
  *  Caller must guarantee that no interfering locks are held.
  *  Returns true if work was performed, false otherwise. */
@@ -115,14 +103,6 @@
 /** Finish any pending work for a grpc_exec_ctx. Must be called before
  *  the instance is destroyed, or work may be lost. */
 void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
-/** Add a closure to be executed in the future.
-    If \a offload_target_or_null is NULL, the closure will be executed at the
-    next exec_ctx.{finish,flush} point.
-    If \a offload_target_or_null is non-NULL, the closure will be scheduled
-    against the workqueue, and a reference to the workqueue will be consumed. */
-void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                         grpc_error *error,
-                         grpc_workqueue *offload_target_or_null);
 /** Returns true if we'd like to leave this execution context as soon as
     possible: useful for deciding whether to do something more or not depending
     on outside context */
@@ -131,11 +111,6 @@
 bool grpc_never_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored);
 /** A finish check that is always ready to finish */
 bool grpc_always_ready_to_finish(grpc_exec_ctx *exec_ctx, void *arg_ignored);
-/** Add a list of closures to be executed at the next flush/finish point.
- *  Leaves \a list empty. */
-void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list,
-                                grpc_workqueue *offload_target_or_null);
 
 void grpc_exec_ctx_global_init(void);
 
diff --git a/src/core/lib/iomgr/executor.c b/src/core/lib/iomgr/executor.c
index 8d7535d..8527755 100644
--- a/src/core/lib/iomgr/executor.c
+++ b/src/core/lib/iomgr/executor.c
@@ -77,10 +77,18 @@
       gpr_mu_unlock(&g_executor.mu);
       break;
     } else {
-      grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
+      grpc_closure *c = g_executor.closures.head;
+      grpc_closure_list_init(&g_executor.closures);
+      gpr_mu_unlock(&g_executor.mu);
+      while (c != NULL) {
+        grpc_closure *next = c->next_data.next;
+        grpc_error *error = c->error_data.error;
+        c->cb(&exec_ctx, c->cb_arg, error);
+        GRPC_ERROR_UNREF(error);
+        c = next;
+      }
+      grpc_exec_ctx_flush(&exec_ctx);
     }
-    gpr_mu_unlock(&g_executor.mu);
-    grpc_exec_ctx_flush(&exec_ctx);
   }
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -112,7 +120,8 @@
   g_executor.pending_join = 1;
 }
 
-void grpc_executor_push(grpc_closure *closure, grpc_error *error) {
+static void executor_push(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
+                          grpc_error *error) {
   gpr_mu_lock(&g_executor.mu);
   if (g_executor.shutting_down == 0) {
     grpc_closure_list_append(&g_executor.closures, closure, error);
@@ -121,9 +130,8 @@
   gpr_mu_unlock(&g_executor.mu);
 }
 
-void grpc_executor_shutdown() {
+void grpc_executor_shutdown(grpc_exec_ctx *exec_ctx) {
   int pending_join;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   gpr_mu_lock(&g_executor.mu);
   pending_join = g_executor.pending_join;
@@ -133,11 +141,24 @@
    * list below because we aren't accepting new work */
 
   /* Execute pending callbacks, some may be performing cleanups */
-  grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
-  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_closure *c = g_executor.closures.head;
+  grpc_closure_list_init(&g_executor.closures);
+  while (c != NULL) {
+    grpc_closure *next = c->next_data.next;
+    grpc_error *error = c->error_data.error;
+    c->cb(exec_ctx, c->cb_arg, error);
+    GRPC_ERROR_UNREF(error);
+    c = next;
+  }
+  grpc_exec_ctx_flush(exec_ctx);
   GPR_ASSERT(grpc_closure_list_empty(g_executor.closures));
   if (pending_join) {
     gpr_thd_join(g_executor.tid);
   }
   gpr_mu_destroy(&g_executor.mu);
 }
+
+static const grpc_closure_scheduler_vtable executor_vtable = {executor_push,
+                                                              executor_push};
+static grpc_closure_scheduler executor_scheduler = {&executor_vtable};
+grpc_closure_scheduler *grpc_executor_scheduler = &executor_scheduler;
diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h
index da9dcd0..1213016 100644
--- a/src/core/lib/iomgr/executor.h
+++ b/src/core/lib/iomgr/executor.h
@@ -43,11 +43,9 @@
  * non-blocking solution available. */
 void grpc_executor_init();
 
-/** Enqueue \a closure for its eventual execution of \a f(arg) on a separate
- * thread */
-void grpc_executor_push(grpc_closure *closure, grpc_error *error);
+extern grpc_closure_scheduler *grpc_executor_scheduler;
 
 /** Shutdown the executor, running all pending work as part of the call */
-void grpc_executor_shutdown();
+void grpc_executor_shutdown(grpc_exec_ctx *exec_ctx);
 
 #endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_H */
diff --git a/src/core/lib/iomgr/iocp_windows.c b/src/core/lib/iomgr/iocp_windows.c
index 60ebe43..f0f4a6f 100644
--- a/src/core/lib/iomgr/iocp_windows.c
+++ b/src/core/lib/iomgr/iocp_windows.c
@@ -80,7 +80,6 @@
   LPOVERLAPPED overlapped;
   grpc_winsocket *socket;
   grpc_winsocket_callback_info *info;
-  grpc_closure *closure = NULL;
   success = GetQueuedCompletionStatus(
       g_iocp, &bytes, &completion_key, &overlapped,
       deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type)));
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 3470b5a..001e528 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -83,11 +83,10 @@
   }
 }
 
-void grpc_iomgr_shutdown(void) {
+void grpc_iomgr_shutdown(grpc_exec_ctx *exec_ctx) {
   gpr_timespec shutdown_deadline = gpr_time_add(
       gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10, GPR_TIMESPAN));
   gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   grpc_iomgr_platform_flush();
 
@@ -104,10 +103,9 @@
       }
       last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
     }
-    if (grpc_timer_check(&exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC),
-                         NULL)) {
+    if (grpc_timer_check(exec_ctx, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL)) {
       gpr_mu_unlock(&g_mu);
-      grpc_exec_ctx_flush(&exec_ctx);
+      grpc_exec_ctx_flush(exec_ctx);
       grpc_iomgr_platform_flush();
       gpr_mu_lock(&g_mu);
       continue;
@@ -139,8 +137,8 @@
   }
   gpr_mu_unlock(&g_mu);
 
-  grpc_timer_list_shutdown(&exec_ctx);
-  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_timer_list_shutdown(exec_ctx);
+  grpc_exec_ctx_flush(exec_ctx);
 
   /* ensure all threads have left g_mu */
   gpr_mu_lock(&g_mu);
diff --git a/src/core/lib/iomgr/iomgr.h b/src/core/lib/iomgr/iomgr.h
index c1cfaf3..245a1e0 100644
--- a/src/core/lib/iomgr/iomgr.h
+++ b/src/core/lib/iomgr/iomgr.h
@@ -34,12 +34,14 @@
 #ifndef GRPC_CORE_LIB_IOMGR_IOMGR_H
 #define GRPC_CORE_LIB_IOMGR_IOMGR_H
 
+#include <grpc/impl/codegen/exec_ctx_fwd.h>
 #include "src/core/lib/iomgr/port.h"
 
 /** Initializes the iomgr. */
 void grpc_iomgr_init(void);
 
-/** Signals the intention to shutdown the iomgr. */
-void grpc_iomgr_shutdown(void);
+/** Signals the intention to shutdown the iomgr. Expects to be able to flush
+ * exec_ctx. */
+void grpc_iomgr_shutdown(grpc_exec_ctx *exec_ctx);
 
 #endif /* GRPC_CORE_LIB_IOMGR_IOMGR_H */
diff --git a/src/core/lib/iomgr/pollset_uv.c b/src/core/lib/iomgr/pollset_uv.c
index 3a74b84..ed3edee 100644
--- a/src/core/lib/iomgr/pollset_uv.c
+++ b/src/core/lib/iomgr/pollset_uv.c
@@ -83,7 +83,7 @@
     // Drain any pending UV callbacks without blocking
     uv_run(uv_default_loop(), UV_RUN_NOWAIT);
   }
-  grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
 }
 
 void grpc_pollset_destroy(grpc_pollset *pollset) {
diff --git a/src/core/lib/iomgr/pollset_windows.c b/src/core/lib/iomgr/pollset_windows.c
index 5540303..2a45e70 100644
--- a/src/core/lib/iomgr/pollset_windows.c
+++ b/src/core/lib/iomgr/pollset_windows.c
@@ -109,7 +109,7 @@
   pollset->shutting_down = 1;
   grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
   if (!pollset->is_iocp_worker) {
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
   } else {
     pollset->on_shutdown = closure;
   }
@@ -167,8 +167,7 @@
       }
 
       if (pollset->shutting_down && pollset->on_shutdown != NULL) {
-        grpc_exec_ctx_sched(exec_ctx, pollset->on_shutdown, GRPC_ERROR_NONE,
-                            NULL);
+        grpc_closure_sched(exec_ctx, pollset->on_shutdown, GRPC_ERROR_NONE);
         pollset->on_shutdown = NULL;
       }
       goto done;
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
index 2759244..e03d16f 100644
--- a/src/core/lib/iomgr/resolve_address.h
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -36,6 +36,7 @@
 
 #include <stddef.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/pollset_set.h"
 
 #define GRPC_MAX_SOCKADDR_SIZE 128
 
@@ -54,6 +55,7 @@
 /* TODO(ctiller): add a timeout here */
 extern void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *addr,
                                     const char *default_port,
+                                    grpc_pollset_set *interested_parties,
                                     grpc_closure *on_done,
                                     grpc_resolved_addresses **addresses);
 /* Destroy resolved addresses */
diff --git a/src/core/lib/iomgr/resolve_address_posix.c b/src/core/lib/iomgr/resolve_address_posix.c
index de791b2..50e470d 100644
--- a/src/core/lib/iomgr/resolve_address_posix.c
+++ b/src/core/lib/iomgr/resolve_address_posix.c
@@ -163,10 +163,9 @@
 static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp,
                               grpc_error *error) {
   request *r = rp;
-  grpc_exec_ctx_sched(
+  grpc_closure_sched(
       exec_ctx, r->on_done,
-      grpc_blocking_resolve_address(r->name, r->default_port, r->addrs_out),
-      NULL);
+      grpc_blocking_resolve_address(r->name, r->default_port, r->addrs_out));
   gpr_free(r->name);
   gpr_free(r->default_port);
   gpr_free(r);
@@ -181,20 +180,22 @@
 
 static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
                                  const char *default_port,
+                                 grpc_pollset_set *interested_parties,
                                  grpc_closure *on_done,
                                  grpc_resolved_addresses **addrs) {
   request *r = gpr_malloc(sizeof(request));
-  grpc_closure_init(&r->request_closure, do_request_thread, r);
+  grpc_closure_init(&r->request_closure, do_request_thread, r,
+                    grpc_executor_scheduler);
   r->name = gpr_strdup(name);
   r->default_port = gpr_strdup(default_port);
   r->on_done = on_done;
   r->addrs_out = addrs;
-  grpc_executor_push(&r->request_closure, GRPC_ERROR_NONE);
+  grpc_closure_sched(exec_ctx, &r->request_closure, GRPC_ERROR_NONE);
 }
 
-void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *name,
-                             const char *default_port, grpc_closure *on_done,
-                             grpc_resolved_addresses **addrs) =
-    resolve_address_impl;
+void (*grpc_resolve_address)(
+    grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
+    grpc_pollset_set *interested_parties, grpc_closure *on_done,
+    grpc_resolved_addresses **addrs) = resolve_address_impl;
 
 #endif
diff --git a/src/core/lib/iomgr/resolve_address_uv.c b/src/core/lib/iomgr/resolve_address_uv.c
index b8295ac..9b5f320 100644
--- a/src/core/lib/iomgr/resolve_address_uv.c
+++ b/src/core/lib/iomgr/resolve_address_uv.c
@@ -98,7 +98,7 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_error *error;
   error = handle_addrinfo_result(status, res, r->addresses);
-  grpc_exec_ctx_sched(&exec_ctx, r->on_done, error, NULL);
+  grpc_closure_sched(&exec_ctx, r->on_done, error);
   grpc_exec_ctx_finish(&exec_ctx);
 
   gpr_free(r->hints);
@@ -181,6 +181,7 @@
 
 static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
                                  const char *default_port,
+                                 grpc_pollset_set *interested_parties,
                                  grpc_closure *on_done,
                                  grpc_resolved_addresses **addrs) {
   uv_getaddrinfo_t *req;
@@ -192,7 +193,7 @@
   int s;
   err = try_split_host_port(name, default_port, &host, &port);
   if (err != GRPC_ERROR_NONE) {
-    grpc_exec_ctx_sched(exec_ctx, on_done, err, NULL);
+    grpc_closure_sched(exec_ctx, on_done, err);
     return;
   }
   r = gpr_malloc(sizeof(request));
@@ -216,16 +217,16 @@
     *addrs = NULL;
     err = GRPC_ERROR_CREATE("getaddrinfo failed");
     err = grpc_error_set_str(err, GRPC_ERROR_STR_OS_ERROR, uv_strerror(s));
-    grpc_exec_ctx_sched(exec_ctx, on_done, err, NULL);
+    grpc_closure_sched(exec_ctx, on_done, err);
     gpr_free(r);
     gpr_free(req);
     gpr_free(hints);
   }
 }
 
-void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *name,
-                             const char *default_port, grpc_closure *on_done,
-                             grpc_resolved_addresses **addrs) =
-    resolve_address_impl;
+void (*grpc_resolve_address)(
+    grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
+    grpc_pollset_set *interested_parties, grpc_closure *on_done,
+    grpc_resolved_addresses **addrs) = resolve_address_impl;
 
 #endif /* GRPC_UV */
diff --git a/src/core/lib/iomgr/resolve_address_windows.c b/src/core/lib/iomgr/resolve_address_windows.c
index e139293..2439ce3 100644
--- a/src/core/lib/iomgr/resolve_address_windows.c
+++ b/src/core/lib/iomgr/resolve_address_windows.c
@@ -154,7 +154,7 @@
   } else {
     GRPC_ERROR_REF(error);
   }
-  grpc_exec_ctx_sched(exec_ctx, r->on_done, error, NULL);
+  grpc_closure_sched(exec_ctx, r->on_done, error);
   gpr_free(r->name);
   gpr_free(r->default_port);
   gpr_free(r);
@@ -169,20 +169,22 @@
 
 static void resolve_address_impl(grpc_exec_ctx *exec_ctx, const char *name,
                                  const char *default_port,
+                                 grpc_pollset_set *interested_parties,
                                  grpc_closure *on_done,
                                  grpc_resolved_addresses **addresses) {
   request *r = gpr_malloc(sizeof(request));
-  grpc_closure_init(&r->request_closure, do_request_thread, r);
+  grpc_closure_init(&r->request_closure, do_request_thread, r,
+                    grpc_executor_scheduler);
   r->name = gpr_strdup(name);
   r->default_port = gpr_strdup(default_port);
   r->on_done = on_done;
   r->addresses = addresses;
-  grpc_executor_push(&r->request_closure, GRPC_ERROR_NONE);
+  grpc_closure_sched(exec_ctx, &r->request_closure, GRPC_ERROR_NONE);
 }
 
-void (*grpc_resolve_address)(grpc_exec_ctx *exec_ctx, const char *name,
-                             const char *default_port, grpc_closure *on_done,
-                             grpc_resolved_addresses **addresses) =
-    resolve_address_impl;
+void (*grpc_resolve_address)(
+    grpc_exec_ctx *exec_ctx, const char *name, const char *default_port,
+    grpc_pollset_set *interested_parties, grpc_closure *on_done,
+    grpc_resolved_addresses **addresses) = resolve_address_impl;
 
 #endif
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 213d296..42a044d 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -257,17 +257,16 @@
   }
 
 done:
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
 }
 
 static void rq_step_sched(grpc_exec_ctx *exec_ctx,
                           grpc_resource_quota *resource_quota) {
   if (resource_quota->step_scheduled) return;
   resource_quota->step_scheduled = true;
-  grpc_resource_quota_internal_ref(resource_quota);
-  grpc_combiner_execute_finally(exec_ctx, resource_quota->combiner,
-                                &resource_quota->rq_step_closure,
-                                GRPC_ERROR_NONE, false);
+  grpc_resource_quota_ref_internal(resource_quota);
+  grpc_closure_sched(exec_ctx, &resource_quota->rq_step_closure,
+                     GRPC_ERROR_NONE);
 }
 
 /* returns true if all allocations are completed */
@@ -294,7 +293,7 @@
     }
     if (resource_user->free_pool >= 0) {
       resource_user->allocating = false;
-      grpc_exec_ctx_enqueue_list(exec_ctx, &resource_user->on_allocated, NULL);
+      grpc_closure_list_sched(exec_ctx, &resource_user->on_allocated);
       gpr_mu_unlock(&resource_user->mu);
     } else {
       rulist_add_head(resource_user, GRPC_RULIST_AWAITING_ALLOCATION);
@@ -345,7 +344,7 @@
             destructive ? "destructive" : "benign");
   }
   resource_quota->reclaiming = true;
-  grpc_resource_quota_internal_ref(resource_quota);
+  grpc_resource_quota_ref_internal(resource_quota);
   grpc_closure *c = resource_user->reclaimers[destructive];
   GPR_ASSERT(c);
   resource_quota->debug_only_last_reclaimer_resource_user = resource_user;
@@ -371,21 +370,10 @@
   gpr_ref(&rc->refs);
 }
 
-static void ru_slice_unref(void *p) {
+static void ru_slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
   ru_slice_refcount *rc = p;
   if (gpr_unref(&rc->refs)) {
-    /* TODO(ctiller): this is dangerous, but I think safe for now:
-       we have no guarantee here that we're at a safe point for creating an
-       execution context, but we have no way of writing this code otherwise.
-       In the future: consider lifting grpc_slice to grpc, and offering an
-       internal_{ref,unref} pair that is execution context aware.
-       Alternatively,
-       make exec_ctx be thread local and 'do the right thing' (whatever that
-       is)
-       if NULL */
-    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resource_user_free(&exec_ctx, rc->resource_user, rc->size);
-    grpc_exec_ctx_finish(&exec_ctx);
+    grpc_resource_user_free(exec_ctx, rc->resource_user, rc->size);
     gpr_free(rc);
   }
 }
@@ -439,7 +427,7 @@
   resource_user->new_reclaimers[destructive] = NULL;
   GPR_ASSERT(resource_user->reclaimers[destructive] == NULL);
   if (gpr_atm_acq_load(&resource_user->shutdown) > 0) {
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED, NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_CANCELLED);
     return false;
   }
   resource_user->reclaimers[destructive] = closure;
@@ -480,10 +468,10 @@
 
 static void ru_shutdown(grpc_exec_ctx *exec_ctx, void *ru, grpc_error *error) {
   grpc_resource_user *resource_user = ru;
-  grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0],
-                      GRPC_ERROR_CANCELLED, NULL);
-  grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
-                      GRPC_ERROR_CANCELLED, NULL);
+  grpc_closure_sched(exec_ctx, resource_user->reclaimers[0],
+                     GRPC_ERROR_CANCELLED);
+  grpc_closure_sched(exec_ctx, resource_user->reclaimers[1],
+                     GRPC_ERROR_CANCELLED);
   resource_user->reclaimers[0] = NULL;
   resource_user->reclaimers[1] = NULL;
   rulist_remove(resource_user, GRPC_RULIST_RECLAIMER_BENIGN);
@@ -496,15 +484,15 @@
   for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
     rulist_remove(resource_user, (grpc_rulist)i);
   }
-  grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[0],
-                      GRPC_ERROR_CANCELLED, NULL);
-  grpc_exec_ctx_sched(exec_ctx, resource_user->reclaimers[1],
-                      GRPC_ERROR_CANCELLED, NULL);
+  grpc_closure_sched(exec_ctx, resource_user->reclaimers[0],
+                     GRPC_ERROR_CANCELLED);
+  grpc_closure_sched(exec_ctx, resource_user->reclaimers[1],
+                     GRPC_ERROR_CANCELLED);
   if (resource_user->free_pool != 0) {
     resource_user->resource_quota->free_pool += resource_user->free_pool;
     rq_step_sched(exec_ctx, resource_user->resource_quota);
   }
-  grpc_resource_quota_internal_unref(exec_ctx, resource_user->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_user->resource_quota);
   gpr_mu_destroy(&resource_user->mu);
   gpr_free(resource_user->name);
   gpr_free(resource_user);
@@ -540,7 +528,7 @@
   a->resource_quota->size += delta;
   a->resource_quota->free_pool += delta;
   rq_step_sched(exec_ctx, a->resource_quota);
-  grpc_resource_quota_internal_unref(exec_ctx, a->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, a->resource_quota);
   gpr_free(a);
 }
 
@@ -549,7 +537,7 @@
   grpc_resource_quota *resource_quota = rq;
   resource_quota->reclaiming = false;
   rq_step_sched(exec_ctx, resource_quota);
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
 }
 
 /*******************************************************************************
@@ -571,16 +559,19 @@
     gpr_asprintf(&resource_quota->name, "anonymous_pool_%" PRIxPTR,
                  (intptr_t)resource_quota);
   }
-  grpc_closure_init(&resource_quota->rq_step_closure, rq_step, resource_quota);
+  grpc_closure_init(
+      &resource_quota->rq_step_closure, rq_step, resource_quota,
+      grpc_combiner_finally_scheduler(resource_quota->combiner, true));
   grpc_closure_init(&resource_quota->rq_reclamation_done_closure,
-                    rq_reclamation_done, resource_quota);
+                    rq_reclamation_done, resource_quota,
+                    grpc_combiner_scheduler(resource_quota->combiner, false));
   for (int i = 0; i < GRPC_RULIST_COUNT; i++) {
     resource_quota->roots[i] = NULL;
   }
   return resource_quota;
 }
 
-void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
+void grpc_resource_quota_unref_internal(grpc_exec_ctx *exec_ctx,
                                         grpc_resource_quota *resource_quota) {
   if (gpr_unref(&resource_quota->refs)) {
     grpc_combiner_destroy(exec_ctx, resource_quota->combiner);
@@ -592,11 +583,11 @@
 /* Public API */
 void grpc_resource_quota_unref(grpc_resource_quota *resource_quota) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-grpc_resource_quota *grpc_resource_quota_internal_ref(
+grpc_resource_quota *grpc_resource_quota_ref_internal(
     grpc_resource_quota *resource_quota) {
   gpr_ref(&resource_quota->refs);
   return resource_quota;
@@ -604,7 +595,7 @@
 
 /* Public API */
 void grpc_resource_quota_ref(grpc_resource_quota *resource_quota) {
-  grpc_resource_quota_internal_ref(resource_quota);
+  grpc_resource_quota_ref_internal(resource_quota);
 }
 
 /* Public API */
@@ -612,11 +603,10 @@
                                 size_t size) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   rq_resize_args *a = gpr_malloc(sizeof(*a));
-  a->resource_quota = grpc_resource_quota_internal_ref(resource_quota);
+  a->resource_quota = grpc_resource_quota_ref_internal(resource_quota);
   a->size = (int64_t)size;
-  grpc_closure_init(&a->closure, rq_resize, a);
-  grpc_combiner_execute(&exec_ctx, resource_quota->combiner, &a->closure,
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_init(&a->closure, rq_resize, a, grpc_schedule_on_exec_ctx);
+  grpc_closure_sched(&exec_ctx, &a->closure, GRPC_ERROR_NONE);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -629,7 +619,7 @@
   for (size_t i = 0; i < channel_args->num_args; i++) {
     if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
       if (channel_args->args[i].type == GRPC_ARG_POINTER) {
-        return grpc_resource_quota_internal_ref(
+        return grpc_resource_quota_ref_internal(
             channel_args->args[i].value.pointer.p);
       } else {
         gpr_log(GPR_DEBUG, GRPC_ARG_RESOURCE_QUOTA " should be a pointer");
@@ -644,7 +634,9 @@
   return rq;
 }
 
-static void rq_destroy(void *rq) { grpc_resource_quota_unref(rq); }
+static void rq_destroy(grpc_exec_ctx *exec_ctx, void *rq) {
+  grpc_resource_quota_unref_internal(exec_ctx, rq);
+}
 
 static int rq_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
 
@@ -661,17 +653,21 @@
     grpc_resource_quota *resource_quota, const char *name) {
   grpc_resource_user *resource_user = gpr_malloc(sizeof(*resource_user));
   resource_user->resource_quota =
-      grpc_resource_quota_internal_ref(resource_quota);
+      grpc_resource_quota_ref_internal(resource_quota);
   grpc_closure_init(&resource_user->allocate_closure, &ru_allocate,
-                    resource_user);
+                    resource_user,
+                    grpc_combiner_scheduler(resource_quota->combiner, false));
   grpc_closure_init(&resource_user->add_to_free_pool_closure,
-                    &ru_add_to_free_pool, resource_user);
+                    &ru_add_to_free_pool, resource_user,
+                    grpc_combiner_scheduler(resource_quota->combiner, false));
   grpc_closure_init(&resource_user->post_reclaimer_closure[0],
-                    &ru_post_benign_reclaimer, resource_user);
+                    &ru_post_benign_reclaimer, resource_user,
+                    grpc_combiner_scheduler(resource_quota->combiner, false));
   grpc_closure_init(&resource_user->post_reclaimer_closure[1],
-                    &ru_post_destructive_reclaimer, resource_user);
-  grpc_closure_init(&resource_user->destroy_closure, &ru_destroy,
-                    resource_user);
+                    &ru_post_destructive_reclaimer, resource_user,
+                    grpc_combiner_scheduler(resource_quota->combiner, false));
+  grpc_closure_init(&resource_user->destroy_closure, &ru_destroy, resource_user,
+                    grpc_combiner_scheduler(resource_quota->combiner, false));
   gpr_mu_init(&resource_user->mu);
   gpr_atm_rel_store(&resource_user->refs, 1);
   gpr_atm_rel_store(&resource_user->shutdown, 0);
@@ -706,9 +702,8 @@
   gpr_atm old = gpr_atm_full_fetch_add(&resource_user->refs, -amount);
   GPR_ASSERT(old >= amount);
   if (old == amount) {
-    grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                          &resource_user->destroy_closure, GRPC_ERROR_NONE,
-                          false);
+    grpc_closure_sched(exec_ctx, &resource_user->destroy_closure,
+                       GRPC_ERROR_NONE);
   }
 }
 
@@ -724,9 +719,12 @@
 void grpc_resource_user_shutdown(grpc_exec_ctx *exec_ctx,
                                  grpc_resource_user *resource_user) {
   if (gpr_atm_full_fetch_add(&resource_user->shutdown, 1) == 0) {
-    grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                          grpc_closure_create(ru_shutdown, resource_user),
-                          GRPC_ERROR_NONE, false);
+    grpc_closure_sched(exec_ctx,
+                       grpc_closure_create(
+                           ru_shutdown, resource_user,
+                           grpc_combiner_scheduler(
+                               resource_user->resource_quota->combiner, false)),
+                       GRPC_ERROR_NONE);
   }
 }
 
@@ -746,12 +744,11 @@
                              GRPC_ERROR_NONE);
     if (!resource_user->allocating) {
       resource_user->allocating = true;
-      grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                            &resource_user->allocate_closure, GRPC_ERROR_NONE,
-                            false);
+      grpc_closure_sched(exec_ctx, &resource_user->allocate_closure,
+                         GRPC_ERROR_NONE);
     }
   } else {
-    grpc_exec_ctx_sched(exec_ctx, optional_on_done, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, optional_on_done, GRPC_ERROR_NONE);
   }
   gpr_mu_unlock(&resource_user->mu);
 }
@@ -770,9 +767,8 @@
   if (is_bigger_than_zero && was_zero_or_negative &&
       !resource_user->added_to_free_pool) {
     resource_user->added_to_free_pool = true;
-    grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                          &resource_user->add_to_free_pool_closure,
-                          GRPC_ERROR_NONE, false);
+    grpc_closure_sched(exec_ctx, &resource_user->add_to_free_pool_closure,
+                       GRPC_ERROR_NONE);
   }
   gpr_mu_unlock(&resource_user->mu);
   ru_unref_by(exec_ctx, resource_user, (gpr_atm)size);
@@ -784,9 +780,9 @@
                                        grpc_closure *closure) {
   GPR_ASSERT(resource_user->new_reclaimers[destructive] == NULL);
   resource_user->new_reclaimers[destructive] = closure;
-  grpc_combiner_execute(exec_ctx, resource_user->resource_quota->combiner,
-                        &resource_user->post_reclaimer_closure[destructive],
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(exec_ctx,
+                     &resource_user->post_reclaimer_closure[destructive],
+                     GRPC_ERROR_NONE);
 }
 
 void grpc_resource_user_finish_reclamation(grpc_exec_ctx *exec_ctx,
@@ -795,18 +791,20 @@
     gpr_log(GPR_DEBUG, "RQ %s %s: reclamation complete",
             resource_user->resource_quota->name, resource_user->name);
   }
-  grpc_combiner_execute(
-      exec_ctx, resource_user->resource_quota->combiner,
-      &resource_user->resource_quota->rq_reclamation_done_closure,
-      GRPC_ERROR_NONE, false);
+  grpc_closure_sched(
+      exec_ctx, &resource_user->resource_quota->rq_reclamation_done_closure,
+      GRPC_ERROR_NONE);
 }
 
 void grpc_resource_user_slice_allocator_init(
     grpc_resource_user_slice_allocator *slice_allocator,
     grpc_resource_user *resource_user, grpc_iomgr_cb_func cb, void *p) {
-  grpc_closure_init(&slice_allocator->on_allocated, ru_allocated_slices,
-                    slice_allocator);
-  grpc_closure_init(&slice_allocator->on_done, cb, p);
+  grpc_closure_init(
+      &slice_allocator->on_allocated, ru_allocated_slices, slice_allocator,
+      grpc_combiner_scheduler(resource_user->resource_quota->combiner, false));
+  grpc_closure_init(
+      &slice_allocator->on_done, cb, p,
+      grpc_combiner_scheduler(resource_user->resource_quota->combiner, false));
   slice_allocator->resource_user = resource_user;
 }
 
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index 0181fd9..ef286c2 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -77,9 +77,9 @@
 
 extern int grpc_resource_quota_trace;
 
-grpc_resource_quota *grpc_resource_quota_internal_ref(
+grpc_resource_quota *grpc_resource_quota_ref_internal(
     grpc_resource_quota *resource_quota);
-void grpc_resource_quota_internal_unref(grpc_exec_ctx *exec_ctx,
+void grpc_resource_quota_unref_internal(grpc_exec_ctx *exec_ctx,
                                         grpc_resource_quota *resource_quota);
 grpc_resource_quota *grpc_resource_quota_from_channel_args(
     const grpc_channel_args *channel_args);
diff --git a/src/core/lib/iomgr/socket_mutator.c b/src/core/lib/iomgr/socket_mutator.c
index 8b1efb6..34b61dc 100644
--- a/src/core/lib/iomgr/socket_mutator.c
+++ b/src/core/lib/iomgr/socket_mutator.c
@@ -76,7 +76,7 @@
   return grpc_socket_mutator_ref(p);
 }
 
-static void socket_mutator_arg_destroy(void *p) {
+static void socket_mutator_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
   grpc_socket_mutator_unref(p);
 }
 
diff --git a/src/core/lib/iomgr/socket_windows.c b/src/core/lib/iomgr/socket_windows.c
index 54911e0..2f2e02f 100644
--- a/src/core/lib/iomgr/socket_windows.c
+++ b/src/core/lib/iomgr/socket_windows.c
@@ -131,7 +131,7 @@
   gpr_mu_lock(&socket->state_mu);
   if (info->has_pending_iocp) {
     info->has_pending_iocp = 0;
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
   } else {
     info->closure = closure;
   }
@@ -154,7 +154,7 @@
   GPR_ASSERT(!info->has_pending_iocp);
   gpr_mu_lock(&socket->state_mu);
   if (info->closure) {
-    grpc_exec_ctx_sched(exec_ctx, info->closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, info->closure, GRPC_ERROR_NONE);
     info->closure = NULL;
   } else {
     info->has_pending_iocp = 1;
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index a3a70a8..9a77c92 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -65,6 +65,7 @@
   grpc_fd *fd;
   gpr_timespec deadline;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   int refs;
   grpc_closure write_closure;
   grpc_pollset_set *interested_parties;
@@ -128,7 +129,7 @@
   if (done) {
     gpr_mu_destroy(&ac->mu);
     gpr_free(ac->addr_str);
-    grpc_channel_args_destroy(ac->channel_args);
+    grpc_channel_args_destroy(exec_ctx, ac->channel_args);
     gpr_free(ac);
   }
 }
@@ -148,8 +149,8 @@
             &channel_args->args[i], options);
       } else if (0 ==
                  strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_internal_ref(
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
             channel_args->args[i].value.pointer.p);
       }
     }
@@ -157,7 +158,7 @@
 
   grpc_endpoint *ep =
       grpc_tcp_create(fd, resource_quota, tcp_read_chunk_size, addr_str);
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   return ep;
 }
 
@@ -262,10 +263,10 @@
   if (done) {
     gpr_mu_destroy(&ac->mu);
     gpr_free(ac->addr_str);
-    grpc_channel_args_destroy(ac->channel_args);
+    grpc_channel_args_destroy(exec_ctx, ac->channel_args);
     gpr_free(ac);
   }
-  grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+  grpc_closure_sched(exec_ctx, closure, error);
 }
 
 static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
@@ -294,7 +295,7 @@
 
   error = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode, &fd);
   if (error != GRPC_ERROR_NONE) {
-    grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+    grpc_closure_sched(exec_ctx, closure, error);
     return;
   }
   if (dsmode == GRPC_DSMODE_IPV4) {
@@ -303,7 +304,7 @@
     addr = &addr4_copy;
   }
   if ((error = prepare_socket(addr, fd, channel_args)) != GRPC_ERROR_NONE) {
-    grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+    grpc_closure_sched(exec_ctx, closure, error);
     return;
   }
 
@@ -321,14 +322,13 @@
   if (err >= 0) {
     *ep =
         grpc_tcp_client_create_from_fd(exec_ctx, fdobj, channel_args, addr_str);
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
     goto done;
   }
 
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
     grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
-    grpc_exec_ctx_sched(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, closure, GRPC_OS_ERROR(errno, "connect"));
     goto done;
   }
 
@@ -343,8 +343,8 @@
   addr_str = NULL;
   gpr_mu_init(&ac->mu);
   ac->refs = 2;
-  ac->write_closure.cb = on_writable;
-  ac->write_closure.cb_arg = ac;
+  grpc_closure_init(&ac->write_closure, on_writable, ac,
+                    grpc_schedule_on_exec_ctx);
   ac->channel_args = grpc_channel_args_copy(channel_args);
 
   if (grpc_tcp_trace) {
@@ -353,9 +353,10 @@
   }
 
   gpr_mu_lock(&ac->mu);
+  grpc_closure_init(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx);
   grpc_timer_init(exec_ctx, &ac->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
   grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
   gpr_mu_unlock(&ac->mu);
 
diff --git a/src/core/lib/iomgr/tcp_client_uv.c b/src/core/lib/iomgr/tcp_client_uv.c
index b07f9ce..5225a54 100644
--- a/src/core/lib/iomgr/tcp_client_uv.c
+++ b/src/core/lib/iomgr/tcp_client_uv.c
@@ -49,6 +49,7 @@
 typedef struct grpc_uv_tcp_connect {
   uv_connect_t connect_req;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   uv_tcp_t *tcp_handle;
   grpc_closure *closure;
   grpc_endpoint **endpoint;
@@ -59,7 +60,7 @@
 
 static void uv_tcp_connect_cleanup(grpc_exec_ctx *exec_ctx,
                                    grpc_uv_tcp_connect *connect) {
-  grpc_resource_quota_internal_unref(exec_ctx, connect->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, connect->resource_quota);
   gpr_free(connect);
 }
 
@@ -110,7 +111,7 @@
   if (done) {
     uv_tcp_connect_cleanup(&exec_ctx, connect);
   }
-  grpc_exec_ctx_sched(&exec_ctx, closure, error, NULL);
+  grpc_closure_sched(&exec_ctx, closure, error);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -128,8 +129,8 @@
   if (channel_args != NULL) {
     for (size_t i = 0; i < channel_args->num_args; i++) {
       if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_internal_ref(
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
             channel_args->args[i].value.pointer.p);
       }
     }
@@ -148,9 +149,11 @@
   uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
                  (const struct sockaddr *)resolved_addr->addr,
                  uv_tc_on_connect);
+  grpc_closure_init(&connect->on_alarm, uv_tc_on_alarm, connect,
+                    grpc_schedule_on_exec_ctx);
   grpc_timer_init(exec_ctx, &connect->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  uv_tc_on_alarm, connect, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
 }
 
 // overridden by api_fuzzer.c
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index 1127588..1e84ec3 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -58,6 +58,7 @@
   grpc_winsocket *socket;
   gpr_timespec deadline;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   char *addr_name;
   int refs;
   grpc_closure on_connect;
@@ -71,7 +72,7 @@
   int done = (--ac->refs == 0);
   gpr_mu_unlock(&ac->mu);
   if (done) {
-    grpc_resource_quota_internal_unref(exec_ctx, ac->resource_quota);
+    grpc_resource_quota_unref_internal(exec_ctx, ac->resource_quota);
     gpr_mu_destroy(&ac->mu);
     gpr_free(ac->addr_name);
     gpr_free(ac);
@@ -129,7 +130,7 @@
   async_connect_unlock_and_cleanup(exec_ctx, ac, socket);
   /* If the connection was aborted, the callback was already called when
      the deadline was met. */
-  grpc_exec_ctx_sched(exec_ctx, on_done, error, NULL);
+  grpc_closure_sched(exec_ctx, on_done, error);
 }
 
 /* Tries to issue one async connection, then schedules both an IOCP
@@ -157,8 +158,8 @@
   if (channel_args != NULL) {
     for (size_t i = 0; i < channel_args->num_args; i++) {
       if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_internal_ref(
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
             channel_args->args[i].value.pointer.p);
       }
     }
@@ -227,9 +228,10 @@
   ac->addr_name = grpc_sockaddr_to_uri(addr);
   ac->endpoint = endpoint;
   ac->resource_quota = resource_quota;
-  grpc_closure_init(&ac->on_connect, on_connect, ac);
+  grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
 
-  grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
+  grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
+  grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm,
                   gpr_now(GPR_CLOCK_MONOTONIC));
   grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
   return;
@@ -246,8 +248,8 @@
   } else if (sock != INVALID_SOCKET) {
     closesocket(sock);
   }
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
-  grpc_exec_ctx_sched(exec_ctx, on_done, final_error, NULL);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+  grpc_closure_sched(exec_ctx, on_done, final_error);
 }
 
 #endif /* GRPC_WINSOCK_SOCKET */
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 540305e..ece4497 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -56,6 +56,7 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
@@ -127,7 +128,7 @@
 static void tcp_free(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
   grpc_fd_orphan(exec_ctx, tcp->em_fd, tcp->release_fd_cb, tcp->release_fd,
                  "tcp_unref_orphan");
-  grpc_slice_buffer_destroy(&tcp->last_read_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &tcp->last_read_buffer);
   grpc_resource_user_unref(exec_ctx, tcp->resource_user);
   gpr_free(tcp->peer_string);
   gpr_free(tcp);
@@ -168,7 +169,7 @@
 static void tcp_destroy(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_network_status_unregister_endpoint(ep);
   grpc_tcp *tcp = (grpc_tcp *)ep;
-  grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &tcp->last_read_buffer);
   TCP_UNREF(exec_ctx, tcp, "destroy");
 }
 
@@ -235,14 +236,15 @@
       /* We've consumed the edge, request a new one */
       grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
     } else {
-      grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+      grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                                 tcp->incoming_buffer);
       call_read_cb(exec_ctx, tcp,
                    tcp_annotate_error(GRPC_OS_ERROR(errno, "recvmsg"), tcp));
       TCP_UNREF(exec_ctx, tcp, "read");
     }
   } else if (read_bytes == 0) {
     /* 0 read size ==> end of stream */
-    grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer);
     call_read_cb(exec_ctx, tcp,
                  tcp_annotate_error(GRPC_ERROR_CREATE("Socket closed"), tcp));
     TCP_UNREF(exec_ctx, tcp, "read");
@@ -268,8 +270,9 @@
                                      grpc_error *error) {
   grpc_tcp *tcp = tcpp;
   if (error != GRPC_ERROR_NONE) {
-    grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
-    grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                               &tcp->last_read_buffer);
     call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
     TCP_UNREF(exec_ctx, tcp, "read");
   } else {
@@ -294,8 +297,9 @@
   GPR_ASSERT(!tcp->finished_edge);
 
   if (error != GRPC_ERROR_NONE) {
-    grpc_slice_buffer_reset_and_unref(tcp->incoming_buffer);
-    grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->incoming_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                               &tcp->last_read_buffer);
     call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
     TCP_UNREF(exec_ctx, tcp, "read");
   } else {
@@ -309,14 +313,14 @@
   GPR_ASSERT(tcp->read_cb == NULL);
   tcp->read_cb = cb;
   tcp->incoming_buffer = incoming_buffer;
-  grpc_slice_buffer_reset_and_unref(incoming_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, incoming_buffer);
   grpc_slice_buffer_swap(incoming_buffer, &tcp->last_read_buffer);
   TCP_REF(tcp, "read");
   if (tcp->finished_edge) {
     tcp->finished_edge = false;
     grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
   } else {
-    grpc_exec_ctx_sched(exec_ctx, &tcp->read_closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, &tcp->read_closure, GRPC_ERROR_NONE);
   }
 }
 
@@ -460,11 +464,10 @@
 
   if (buf->length == 0) {
     GPR_TIMER_END("tcp_write", 0);
-    grpc_exec_ctx_sched(exec_ctx, cb,
-                        grpc_fd_is_shutdown(tcp->em_fd)
-                            ? tcp_annotate_error(GRPC_ERROR_CREATE("EOF"), tcp)
-                            : GRPC_ERROR_NONE,
-                        NULL);
+    grpc_closure_sched(exec_ctx, cb,
+                       grpc_fd_is_shutdown(tcp->em_fd)
+                           ? tcp_annotate_error(GRPC_ERROR_CREATE("EOF"), tcp)
+                           : GRPC_ERROR_NONE);
     return;
   }
   tcp->outgoing_buffer = buf;
@@ -484,7 +487,7 @@
       gpr_log(GPR_DEBUG, "write: %s", str);
       grpc_error_free_string(str);
     }
-    grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+    grpc_closure_sched(exec_ctx, cb, error);
   }
 
   GPR_TIMER_END("tcp_write", 0);
@@ -552,10 +555,10 @@
   gpr_ref_init(&tcp->refcount, 1);
   gpr_atm_no_barrier_store(&tcp->shutdown_count, 0);
   tcp->em_fd = em_fd;
-  tcp->read_closure.cb = tcp_handle_read;
-  tcp->read_closure.cb_arg = tcp;
-  tcp->write_closure.cb = tcp_handle_write;
-  tcp->write_closure.cb_arg = tcp;
+  grpc_closure_init(&tcp->read_closure, tcp_handle_read, tcp,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&tcp->write_closure, tcp_handle_write, tcp,
+                    grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&tcp->last_read_buffer);
   tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
   grpc_resource_user_slice_allocator_init(
@@ -579,7 +582,7 @@
   GPR_ASSERT(ep->vtable == &vtable);
   tcp->release_fd = fd;
   tcp->release_fd_cb = done;
-  grpc_slice_buffer_reset_and_unref(&tcp->last_read_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &tcp->last_read_buffer);
   TCP_UNREF(exec_ctx, tcp, "destroy");
 }
 
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index 179f47e..20efb67 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -167,18 +167,18 @@
         s->so_reuseport =
             has_so_reuseport && (args->args[i].value.integer != 0);
       } else {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE(GRPC_ARG_ALLOW_REUSEPORT
                                  " must be an integer");
       }
     } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
       if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         s->resource_quota =
-            grpc_resource_quota_internal_ref(args->args[i].value.pointer.p);
+            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
       } else {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA
                                  " must be a pointer to a buffer pool");
@@ -208,7 +208,7 @@
   GPR_ASSERT(s->shutdown);
   gpr_mu_unlock(&s->mu);
   if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
   }
 
   gpr_mu_destroy(&s->mu);
@@ -219,7 +219,7 @@
     gpr_free(sp);
   }
 
-  grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
 
   gpr_free(s);
 }
@@ -254,8 +254,8 @@
     grpc_tcp_listener *sp;
     for (sp = s->head; sp; sp = sp->next) {
       grpc_unlink_if_unix_domain_socket(&sp->addr);
-      sp->destroyed_closure.cb = destroyed_port;
-      sp->destroyed_closure.cb_arg = s;
+      grpc_closure_init(&sp->destroyed_closure, destroyed_port, s,
+                        grpc_schedule_on_exec_ctx);
       grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL,
                      "tcp_listener_shutdown");
     }
@@ -723,8 +723,8 @@
           "clone_port", clone_port(sp, (unsigned)(pollset_count - 1))));
       for (i = 0; i < pollset_count; i++) {
         grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
-        sp->read_closure.cb = on_read;
-        sp->read_closure.cb_arg = sp;
+        grpc_closure_init(&sp->read_closure, on_read, sp,
+                          grpc_schedule_on_exec_ctx);
         grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
         s->active_ports++;
         sp = sp->next;
@@ -733,8 +733,8 @@
       for (i = 0; i < pollset_count; i++) {
         grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
       }
-      sp->read_closure.cb = on_read;
-      sp->read_closure.cb_arg = sp;
+      grpc_closure_init(&sp->read_closure, on_read, sp,
+                        grpc_schedule_on_exec_ctx);
       grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
       s->active_ports++;
       sp = sp->next;
@@ -760,7 +760,7 @@
   if (gpr_unref(&s->refs)) {
     grpc_tcp_server_shutdown_listeners(exec_ctx, s);
     gpr_mu_lock(&s->mu);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &s->shutdown_starting, NULL);
+    grpc_closure_list_sched(exec_ctx, &s->shutdown_starting);
     gpr_mu_unlock(&s->mu);
     tcp_server_destroy(exec_ctx, s);
   }
diff --git a/src/core/lib/iomgr/tcp_server_uv.c b/src/core/lib/iomgr/tcp_server_uv.c
index e1a174c..eed2773 100644
--- a/src/core/lib/iomgr/tcp_server_uv.c
+++ b/src/core/lib/iomgr/tcp_server_uv.c
@@ -89,11 +89,11 @@
   for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
     if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
       if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         s->resource_quota =
-            grpc_resource_quota_internal_ref(args->args[i].value.pointer.p);
+            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
       } else {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA
                                  " must be a pointer to a buffer pool");
@@ -126,7 +126,7 @@
 
 static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
   if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
   }
 
   while (s->head) {
@@ -136,7 +136,7 @@
     gpr_free(sp->handle);
     gpr_free(sp);
   }
-  grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
   gpr_free(s);
 }
 
@@ -170,7 +170,7 @@
   if (gpr_unref(&s->refs)) {
     /* Complete shutdown_starting work before destroying. */
     grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
+    grpc_closure_list_sched(&local_exec_ctx, &s->shutdown_starting);
     if (exec_ctx == NULL) {
       grpc_exec_ctx_flush(&local_exec_ctx);
       tcp_server_destroy(&local_exec_ctx, s);
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index b0c8586..dafe851 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -116,11 +116,11 @@
   for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
     if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
       if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         s->resource_quota =
-            grpc_resource_quota_internal_ref(args->args[i].value.pointer.p);
+            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
       } else {
-        grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE(GRPC_ARG_RESOURCE_QUOTA
                                  " must be a pointer to a buffer pool");
@@ -155,18 +155,19 @@
     grpc_winsocket_destroy(sp->socket);
     gpr_free(sp);
   }
-  grpc_resource_quota_internal_unref(exec_ctx, s->resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
   gpr_free(s);
 }
 
 static void finish_shutdown_locked(grpc_exec_ctx *exec_ctx,
                                    grpc_tcp_server *s) {
   if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
   }
 
-  grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(destroy_server, s),
-                      GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, grpc_closure_create(destroy_server, s,
+                                                   grpc_schedule_on_exec_ctx),
+                     GRPC_ERROR_NONE);
 }
 
 grpc_tcp_server *grpc_tcp_server_ref(grpc_tcp_server *s) {
@@ -183,7 +184,6 @@
 }
 
 static void tcp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
-  int immediately_done = 0;
   grpc_tcp_listener *sp;
   gpr_mu_lock(&s->mu);
 
@@ -204,7 +204,7 @@
   if (gpr_unref(&s->refs)) {
     grpc_tcp_server_shutdown_listeners(exec_ctx, s);
     gpr_mu_lock(&s->mu);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &s->shutdown_starting, NULL);
+    grpc_closure_list_sched(exec_ctx, &s->shutdown_starting);
     gpr_mu_unlock(&s->mu);
     tcp_server_destroy(exec_ctx, s);
   }
@@ -239,7 +239,7 @@
     error = GRPC_WSA_ERROR(WSAGetLastError(), "getsockname");
     goto failure;
   }
-  sockname_temp.len = sockname_temp_len;
+  sockname_temp.len = (size_t)sockname_temp_len;
 
   *port = grpc_sockaddr_get_port(&sockname_temp);
   return GRPC_ERROR_NONE;
@@ -247,7 +247,7 @@
 failure:
   GPR_ASSERT(error != GRPC_ERROR_NONE);
   char *tgtaddr = grpc_sockaddr_to_uri(addr);
-  grpc_error *final_error = grpc_error_set_int(
+  grpc_error_set_int(
       grpc_error_set_str(GRPC_ERROR_CREATE_REFERENCING(
                              "Failed to prepare server socket", &error, 1),
                          GRPC_ERROR_STR_TARGET_ADDRESS, tgtaddr),
@@ -260,7 +260,6 @@
 
 static void decrement_active_ports_and_notify_locked(grpc_exec_ctx *exec_ctx,
                                                      grpc_tcp_listener *sp) {
-  int notify = 0;
   sp->shutting_down = 0;
   GPR_ASSERT(sp->server->active_ports > 0);
   if (0 == --sp->server->active_ports) {
@@ -374,7 +373,7 @@
       int peer_name_len = (int)peer_name.len;
       err =
           getpeername(sock, (struct sockaddr *)peer_name.addr, &peer_name_len);
-      peer_name.len = peer_name_len;
+      peer_name.len = (size_t)peer_name_len;
       if (!err) {
         peer_name_string = grpc_sockaddr_to_uri(&peer_name);
       } else {
@@ -465,7 +464,7 @@
   sp->new_socket = INVALID_SOCKET;
   sp->port = port;
   sp->port_index = port_index;
-  grpc_closure_init(&sp->on_accept, on_accept, sp);
+  grpc_closure_init(&sp->on_accept, on_accept, sp, grpc_schedule_on_exec_ctx);
   GPR_ASSERT(sp->socket);
   gpr_mu_unlock(&s->mu);
   *listener = sp;
@@ -497,7 +496,7 @@
       if (0 == getsockname(sp->socket->socket,
                            (struct sockaddr *)sockname_temp.addr,
                            &sockname_temp_len)) {
-        sockname_temp.len = sockname_temp_len;
+        sockname_temp.len = (size_t)sockname_temp_len;
         *port = grpc_sockaddr_get_port(&sockname_temp);
         if (*port > 0) {
           allocated_addr = gpr_malloc(sizeof(grpc_resolved_address));
diff --git a/src/core/lib/iomgr/tcp_uv.c b/src/core/lib/iomgr/tcp_uv.c
index 6e2ad1d..3ddc797 100644
--- a/src/core/lib/iomgr/tcp_uv.c
+++ b/src/core/lib/iomgr/tcp_uv.c
@@ -169,7 +169,7 @@
     // nread < 0: Error
     error = GRPC_ERROR_CREATE("TCP Read failed");
   }
-  grpc_exec_ctx_sched(&exec_ctx, cb, error, NULL);
+  grpc_closure_sched(&exec_ctx, cb, error);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -181,7 +181,7 @@
   GPR_ASSERT(tcp->read_cb == NULL);
   tcp->read_cb = cb;
   tcp->read_slices = read_slices;
-  grpc_slice_buffer_reset_and_unref(read_slices);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices);
   TCP_REF(tcp, "read");
   // TODO(murgatroid99): figure out what the return value here means
   status =
@@ -190,7 +190,7 @@
     error = GRPC_ERROR_CREATE("TCP Read failed at start");
     error =
         grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR, uv_strerror(status));
-    grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+    grpc_closure_sched(exec_ctx, cb, error);
   }
   if (grpc_tcp_trace) {
     const char *str = grpc_error_string(error);
@@ -217,7 +217,7 @@
   gpr_free(tcp->write_buffers);
   grpc_resource_user_free(&exec_ctx, tcp->resource_user,
                           sizeof(uv_buf_t) * tcp->write_slices->count);
-  grpc_exec_ctx_sched(&exec_ctx, cb, error, NULL);
+  grpc_closure_sched(&exec_ctx, cb, error);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -243,8 +243,8 @@
   }
 
   if (tcp->shutting_down) {
-    grpc_exec_ctx_sched(exec_ctx, cb,
-                        GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
+    grpc_closure_sched(exec_ctx, cb,
+                       GRPC_ERROR_CREATE("TCP socket is shutting down"));
     return;
   }
 
@@ -254,7 +254,7 @@
   if (tcp->write_slices->count == 0) {
     // No slices means we don't have to do anything,
     // and libuv doesn't like empty writes
-    grpc_exec_ctx_sched(exec_ctx, cb, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_NONE);
     return;
   }
 
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index d4613b6..84f791b 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -53,6 +53,7 @@
 #include "src/core/lib/iomgr/socket_windows.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/timer.h"
+#include "src/core/lib/slice/slice_internal.h"
 
 #if defined(__MSYS__) && defined(GPR_ARCH_64)
 /* Nasty workaround for nasty bug when using the 64 bits msys compiler
@@ -174,13 +175,13 @@
       char *utf8_message = gpr_format_message(info->wsa_error);
       error = GRPC_ERROR_CREATE(utf8_message);
       gpr_free(utf8_message);
-      grpc_slice_unref(tcp->read_slice);
+      grpc_slice_unref_internal(exec_ctx, tcp->read_slice);
     } else {
       if (info->bytes_transfered != 0 && !tcp->shutting_down) {
         sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, info->bytes_transfered);
         grpc_slice_buffer_add(tcp->read_slices, sub);
       } else {
-        grpc_slice_unref(tcp->read_slice);
+        grpc_slice_unref_internal(exec_ctx, tcp->read_slice);
         error = GRPC_ERROR_CREATE("End of TCP stream");
       }
     }
@@ -188,7 +189,7 @@
 
   tcp->read_cb = NULL;
   TCP_UNREF(exec_ctx, tcp, "read");
-  grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+  grpc_closure_sched(exec_ctx, cb, error);
 }
 
 static void win_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -202,14 +203,14 @@
   WSABUF buffer;
 
   if (tcp->shutting_down) {
-    grpc_exec_ctx_sched(exec_ctx, cb,
-                        GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
+    grpc_closure_sched(exec_ctx, cb,
+                       GRPC_ERROR_CREATE("TCP socket is shutting down"));
     return;
   }
 
   tcp->read_cb = cb;
   tcp->read_slices = read_slices;
-  grpc_slice_buffer_reset_and_unref(read_slices);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices);
 
   tcp->read_slice = grpc_slice_malloc(8192);
 
@@ -227,7 +228,7 @@
   /* Did we get data immediately ? Yay. */
   if (info->wsa_error != WSAEWOULDBLOCK) {
     info->bytes_transfered = bytes_read;
-    grpc_exec_ctx_sched(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, &tcp->on_read, GRPC_ERROR_NONE);
     return;
   }
 
@@ -240,8 +241,8 @@
     int wsa_error = WSAGetLastError();
     if (wsa_error != WSA_IO_PENDING) {
       info->wsa_error = wsa_error;
-      grpc_exec_ctx_sched(exec_ctx, &tcp->on_read,
-                          GRPC_WSA_ERROR(info->wsa_error, "WSARecv"), NULL);
+      grpc_closure_sched(exec_ctx, &tcp->on_read,
+                         GRPC_WSA_ERROR(info->wsa_error, "WSARecv"));
       return;
     }
   }
@@ -272,7 +273,7 @@
   }
 
   TCP_UNREF(exec_ctx, tcp, "write");
-  grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+  grpc_closure_sched(exec_ctx, cb, error);
 }
 
 /* Initiates a write. */
@@ -290,8 +291,8 @@
   size_t len;
 
   if (tcp->shutting_down) {
-    grpc_exec_ctx_sched(exec_ctx, cb,
-                        GRPC_ERROR_CREATE("TCP socket is shutting down"), NULL);
+    grpc_closure_sched(exec_ctx, cb,
+                       GRPC_ERROR_CREATE("TCP socket is shutting down"));
     return;
   }
 
@@ -322,7 +323,7 @@
     grpc_error *error = status == 0
                             ? GRPC_ERROR_NONE
                             : GRPC_WSA_ERROR(info->wsa_error, "WSASend");
-    grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+    grpc_closure_sched(exec_ctx, cb, error);
     if (allocated) gpr_free(allocated);
     return;
   }
@@ -340,8 +341,7 @@
     int wsa_error = WSAGetLastError();
     if (wsa_error != WSA_IO_PENDING) {
       TCP_UNREF(exec_ctx, tcp, "write");
-      grpc_exec_ctx_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"),
-                          NULL);
+      grpc_closure_sched(exec_ctx, cb, GRPC_WSA_ERROR(wsa_error, "WSASend"));
       return;
     }
   }
@@ -424,8 +424,8 @@
   tcp->socket = socket;
   gpr_mu_init(&tcp->mu);
   gpr_ref_init(&tcp->refcount, 1);
-  grpc_closure_init(&tcp->on_read, on_read, tcp);
-  grpc_closure_init(&tcp->on_write, on_write, tcp);
+  grpc_closure_init(&tcp->on_read, on_read, tcp, grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&tcp->on_write, on_write, tcp, grpc_schedule_on_exec_ctx);
   tcp->peer_string = gpr_strdup(peer_string);
   tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
   /* Tell network status tracking code about the new endpoint */
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index 20fe98c..d84a278 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -49,15 +49,15 @@
 
 typedef struct grpc_timer grpc_timer;
 
-/* Initialize *timer. When expired or canceled, timer_cb will be called with
-   *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or
-   was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called
-   exactly once, and application code should check the error to determine
-   how it was invoked. The application callback is also responsible for
-   maintaining information about when to free up any user-level state. */
+/* Initialize *timer. When expired or canceled, closure will be called with
+   error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled
+   (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called exactly once, and
+   application code should check the error to determine how it was invoked. The
+   application callback is also responsible for maintaining information about
+   when to free up any user-level state. */
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now);
+                     gpr_timespec deadline, grpc_closure *closure,
+                     gpr_timespec now);
 
 /* Note that there is no timer destroy function. This is because the
    timer is a one-time occurrence with a guarantee that the callback will
diff --git a/src/core/lib/iomgr/timer_generic.c b/src/core/lib/iomgr/timer_generic.c
index 00058f9..40c8351 100644
--- a/src/core/lib/iomgr/timer_generic.c
+++ b/src/core/lib/iomgr/timer_generic.c
@@ -178,28 +178,27 @@
 }
 
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now) {
+                     gpr_timespec deadline, grpc_closure *closure,
+                     gpr_timespec now) {
   int is_first_timer = 0;
   shard_type *shard = &g_shards[shard_idx(timer)];
   GPR_ASSERT(deadline.clock_type == g_clock_type);
   GPR_ASSERT(now.clock_type == g_clock_type);
-  grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg);
+  timer->closure = closure;
   timer->deadline = deadline;
   timer->triggered = 0;
 
   if (!g_initialized) {
     timer->triggered = 1;
-    grpc_exec_ctx_sched(
-        exec_ctx, &timer->closure,
-        GRPC_ERROR_CREATE("Attempt to create timer before initialization"),
-        NULL);
+    grpc_closure_sched(
+        exec_ctx, timer->closure,
+        GRPC_ERROR_CREATE("Attempt to create timer before initialization"));
     return;
   }
 
   if (gpr_time_cmp(deadline, now) <= 0) {
     timer->triggered = 1;
-    grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE);
     return;
   }
 
@@ -251,7 +250,7 @@
   shard_type *shard = &g_shards[shard_idx(timer)];
   gpr_mu_lock(&shard->mu);
   if (!timer->triggered) {
-    grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED, NULL);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
     timer->triggered = 1;
     if (timer->heap_index == INVALID_HEAP_INDEX) {
       list_remove(timer);
@@ -317,7 +316,7 @@
   grpc_timer *timer;
   gpr_mu_lock(&shard->mu);
   while ((timer = pop_one(shard, now))) {
-    grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_REF(error), NULL);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_REF(error));
     n++;
   }
   *new_min_deadline = compute_min_deadline(shard);
diff --git a/src/core/lib/iomgr/timer_generic.h b/src/core/lib/iomgr/timer_generic.h
index e4494ad..9d901c7 100644
--- a/src/core/lib/iomgr/timer_generic.h
+++ b/src/core/lib/iomgr/timer_generic.h
@@ -43,7 +43,7 @@
   int triggered;
   struct grpc_timer *next;
   struct grpc_timer *prev;
-  grpc_closure closure;
+  grpc_closure *closure;
 };
 
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */
diff --git a/src/core/lib/iomgr/timer_uv.c b/src/core/lib/iomgr/timer_uv.c
index cfcb892..fa2cdee 100644
--- a/src/core/lib/iomgr/timer_uv.c
+++ b/src/core/lib/iomgr/timer_uv.c
@@ -55,20 +55,20 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GPR_ASSERT(!timer->triggered);
   timer->triggered = 1;
-  grpc_exec_ctx_sched(&exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(&exec_ctx, timer->closure, GRPC_ERROR_NONE);
   stop_uv_timer(handle);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now) {
+                     gpr_timespec deadline, grpc_closure *closure,
+                     gpr_timespec now) {
   uint64_t timeout;
   uv_timer_t *uv_timer;
-  grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg);
+  timer->closure = closure;
   if (gpr_time_cmp(deadline, now) <= 0) {
     timer->triggered = 1;
-    grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE);
     return;
   }
   timer->triggered = 0;
@@ -83,7 +83,7 @@
 void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
   if (!timer->triggered) {
     timer->triggered = 1;
-    grpc_exec_ctx_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED, NULL);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
     stop_uv_timer((uv_timer_t *)timer->uv_timer);
   }
 }
diff --git a/src/core/lib/iomgr/timer_uv.h b/src/core/lib/iomgr/timer_uv.h
index 3de383e..13cf8bd 100644
--- a/src/core/lib/iomgr/timer_uv.h
+++ b/src/core/lib/iomgr/timer_uv.h
@@ -37,7 +37,7 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 struct grpc_timer {
-  grpc_closure closure;
+  grpc_closure *closure;
   /* This is actually a uv_timer_t*, but we want to keep platform-specific
      types out of headers */
   void *uv_timer;
diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c
index 3c24ea9..dfbd295 100644
--- a/src/core/lib/iomgr/udp_server.c
+++ b/src/core/lib/iomgr/udp_server.c
@@ -126,7 +126,7 @@
 
 static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) {
   if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, s->shutdown_complete, GRPC_ERROR_NONE);
   }
 
   gpr_mu_destroy(&s->mu);
@@ -170,8 +170,8 @@
     for (sp = s->head; sp; sp = sp->next) {
       grpc_unlink_if_unix_domain_socket(&sp->addr);
 
-      sp->destroyed_closure.cb = destroyed_port;
-      sp->destroyed_closure.cb_arg = s;
+      grpc_closure_init(&sp->destroyed_closure, destroyed_port, s,
+                        grpc_schedule_on_exec_ctx);
 
       /* Call the orphan_cb to signal that the FD is about to be closed and
        * should no longer be used. */
@@ -446,8 +446,8 @@
     for (i = 0; i < pollset_count; i++) {
       grpc_pollset_add_fd(exec_ctx, pollsets[i], sp->emfd);
     }
-    sp->read_closure.cb = on_read;
-    sp->read_closure.cb_arg = sp;
+    grpc_closure_init(&sp->read_closure, on_read, sp,
+                      grpc_schedule_on_exec_ctx);
     grpc_fd_notify_on_read(exec_ctx, sp->emfd, &sp->read_closure);
 
     s->active_ports++;
diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h
index 73d9849..371b0f5 100644
--- a/src/core/lib/iomgr/workqueue.h
+++ b/src/core/lib/iomgr/workqueue.h
@@ -72,17 +72,16 @@
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
 #endif
 
-/** Add a work item to a workqueue. Items added to a work queue will be started
-    in approximately the order they were enqueued, on some thread that may or
-    may not be the current thread. Successive closures enqueued onto a workqueue
-    MAY be executed concurrently.
+/** Fetch the workqueue closure scheduler. Items added to a work queue will be
+    started in approximately the order they were enqueued, on some thread that
+    may or may not be the current thread. Successive closures enqueued onto a
+    workqueue MAY be executed concurrently.
 
     It is generally more expensive to add a closure to a workqueue than to the
     execution context, both in terms of CPU work and in execution latency.
 
     Use work queues when it's important that other threads be given a chance to
     tackle some workload. */
-void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                            grpc_closure *closure, grpc_error *error);
+grpc_closure_scheduler *grpc_workqueue_scheduler(grpc_workqueue *workqueue);
 
 #endif /* GRPC_CORE_LIB_IOMGR_WORKQUEUE_H */
diff --git a/src/core/lib/iomgr/workqueue_uv.c b/src/core/lib/iomgr/workqueue_uv.c
index e58ca47..4d61b40 100644
--- a/src/core/lib/iomgr/workqueue_uv.c
+++ b/src/core/lib/iomgr/workqueue_uv.c
@@ -58,9 +58,8 @@
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
 #endif
 
-void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                            grpc_closure *closure, grpc_error *error) {
-  grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+grpc_closure_scheduler *grpc_workqueue_scheduler(grpc_workqueue *workqueue) {
+  return grpc_schedule_on_exec_ctx;
 }
 
 #endif /* GPR_UV */
diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c
index 5c93d3c..234b47c 100644
--- a/src/core/lib/iomgr/workqueue_windows.c
+++ b/src/core/lib/iomgr/workqueue_windows.c
@@ -56,9 +56,8 @@
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
 #endif
 
-void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                            grpc_closure *closure, grpc_error *error) {
-  grpc_exec_ctx_sched(exec_ctx, closure, error, NULL);
+grpc_closure_scheduler *grpc_workqueue_scheduler(grpc_workqueue *workqueue) {
+  return grpc_schedule_on_exec_ctx;
 }
 
 #endif /* GPR_WINDOWS */
diff --git a/src/core/lib/security/context/security_context.c b/src/core/lib/security/context/security_context.c
index 2204fad..fe82fab 100644
--- a/src/core/lib/security/context/security_context.c
+++ b/src/core/lib/security/context/security_context.c
@@ -47,6 +47,7 @@
 
 grpc_call_error grpc_call_set_credentials(grpc_call *call,
                                           grpc_call_credentials *creds) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_client_security_context *ctx = NULL;
   GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2,
                  (call, creds));
@@ -62,9 +63,10 @@
     grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx,
                           grpc_client_security_context_destroy);
   } else {
-    grpc_call_credentials_unref(ctx->creds);
+    grpc_call_credentials_unref(&exec_ctx, ctx->creds);
     ctx->creds = grpc_call_credentials_ref(creds);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   return GRPC_CALL_OK;
 }
 
@@ -96,13 +98,15 @@
 }
 
 void grpc_client_security_context_destroy(void *ctx) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_client_security_context *c = (grpc_client_security_context *)ctx;
-  grpc_call_credentials_unref(c->creds);
+  grpc_call_credentials_unref(&exec_ctx, c->creds);
   GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
   if (c->extension.instance != NULL && c->extension.destroy != NULL) {
     c->extension.destroy(c->extension.instance);
   }
   gpr_free(ctx);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 /* --- grpc_server_security_context --- */
@@ -307,7 +311,7 @@
   memset(property, 0, sizeof(grpc_auth_property));
 }
 
-static void auth_context_pointer_arg_destroy(void *p) {
+static void auth_context_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
   GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg");
 }
 
diff --git a/src/core/lib/security/credentials/composite/composite_credentials.c b/src/core/lib/security/credentials/composite/composite_credentials.c
index d55d00b..be1588d 100644
--- a/src/core/lib/security/credentials/composite/composite_credentials.c
+++ b/src/core/lib/security/credentials/composite/composite_credentials.c
@@ -54,18 +54,20 @@
   grpc_credentials_metadata_cb cb;
 } grpc_composite_call_credentials_metadata_context;
 
-static void composite_call_destruct(grpc_call_credentials *creds) {
+static void composite_call_destruct(grpc_exec_ctx *exec_ctx,
+                                    grpc_call_credentials *creds) {
   grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
   size_t i;
   for (i = 0; i < c->inner.num_creds; i++) {
-    grpc_call_credentials_unref(c->inner.creds_array[i]);
+    grpc_call_credentials_unref(exec_ctx, c->inner.creds_array[i]);
   }
   gpr_free(c->inner.creds_array);
 }
 
 static void composite_call_md_context_destroy(
+    grpc_exec_ctx *exec_ctx,
     grpc_composite_call_credentials_metadata_context *ctx) {
-  grpc_credentials_md_store_unref(ctx->md_elems);
+  grpc_credentials_md_store_unref(exec_ctx, ctx->md_elems);
   gpr_free(ctx);
 }
 
@@ -103,7 +105,7 @@
   /* We're done!. */
   ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
           ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK, NULL);
-  composite_call_md_context_destroy(ctx);
+  composite_call_md_context_destroy(exec_ctx, ctx);
 }
 
 static void composite_call_get_request_metadata(
@@ -209,17 +211,19 @@
 
 /* -- Composite channel credentials. -- */
 
-static void composite_channel_destruct(grpc_channel_credentials *creds) {
+static void composite_channel_destruct(grpc_exec_ctx *exec_ctx,
+                                       grpc_channel_credentials *creds) {
   grpc_composite_channel_credentials *c =
       (grpc_composite_channel_credentials *)creds;
-  grpc_channel_credentials_unref(c->inner_creds);
-  grpc_call_credentials_unref(c->call_creds);
+  grpc_channel_credentials_unref(exec_ctx, c->inner_creds);
+  grpc_call_credentials_unref(exec_ctx, c->call_creds);
 }
 
 static grpc_security_status composite_channel_create_security_connector(
-    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds,
+    grpc_call_credentials *call_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
   grpc_composite_channel_credentials *c =
       (grpc_composite_channel_credentials *)creds;
   grpc_security_status status = GRPC_SECURITY_ERROR;
@@ -233,11 +237,12 @@
     grpc_call_credentials *composite_call_creds =
         grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
     status = c->inner_creds->vtable->create_security_connector(
-        c->inner_creds, composite_call_creds, target, args, sc, new_args);
-    grpc_call_credentials_unref(composite_call_creds);
+        exec_ctx, c->inner_creds, composite_call_creds, target, args, sc,
+        new_args);
+    grpc_call_credentials_unref(exec_ctx, composite_call_creds);
   } else {
     status = c->inner_creds->vtable->create_security_connector(
-        c->inner_creds, c->call_creds, target, args, sc, new_args);
+        exec_ctx, c->inner_creds, c->call_creds, target, args, sc, new_args);
   }
   return status;
 }
diff --git a/src/core/lib/security/credentials/credentials.c b/src/core/lib/security/credentials/credentials.c
index 1149e5c..9781a22 100644
--- a/src/core/lib/security/credentials/credentials.c
+++ b/src/core/lib/security/credentials/credentials.c
@@ -66,8 +66,8 @@
 }
 
 void grpc_credentials_metadata_request_destroy(
-    grpc_credentials_metadata_request *r) {
-  grpc_call_credentials_unref(r->creds);
+    grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *r) {
+  grpc_call_credentials_unref(exec_ctx, r->creds);
   grpc_http_response_destroy(&r->response);
   gpr_free(r);
 }
@@ -79,17 +79,22 @@
   return creds;
 }
 
-void grpc_channel_credentials_unref(grpc_channel_credentials *creds) {
+void grpc_channel_credentials_unref(grpc_exec_ctx *exec_ctx,
+                                    grpc_channel_credentials *creds) {
   if (creds == NULL) return;
   if (gpr_unref(&creds->refcount)) {
-    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    if (creds->vtable->destruct != NULL) {
+      creds->vtable->destruct(exec_ctx, creds);
+    }
     gpr_free(creds);
   }
 }
 
 void grpc_channel_credentials_release(grpc_channel_credentials *creds) {
   GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds));
-  grpc_channel_credentials_unref(creds);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_channel_credentials_unref(&exec_ctx, creds);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) {
@@ -98,17 +103,22 @@
   return creds;
 }
 
-void grpc_call_credentials_unref(grpc_call_credentials *creds) {
+void grpc_call_credentials_unref(grpc_exec_ctx *exec_ctx,
+                                 grpc_call_credentials *creds) {
   if (creds == NULL) return;
   if (gpr_unref(&creds->refcount)) {
-    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    if (creds->vtable->destruct != NULL) {
+      creds->vtable->destruct(exec_ctx, creds);
+    }
     gpr_free(creds);
   }
 }
 
 void grpc_call_credentials_release(grpc_call_credentials *creds) {
   GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds));
-  grpc_call_credentials_unref(creds);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_call_credentials_unref(&exec_ctx, creds);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 void grpc_call_credentials_get_request_metadata(
@@ -126,16 +136,16 @@
 }
 
 grpc_security_status grpc_channel_credentials_create_security_connector(
-    grpc_channel_credentials *channel_creds, const char *target,
-    const grpc_channel_args *args, grpc_channel_security_connector **sc,
-    grpc_channel_args **new_args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *channel_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
   *new_args = NULL;
   if (channel_creds == NULL) {
     return GRPC_SECURITY_ERROR;
   }
   GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL);
   return channel_creds->vtable->create_security_connector(
-      channel_creds, NULL, target, args, sc, new_args);
+      exec_ctx, channel_creds, NULL, target, args, sc, new_args);
 }
 
 grpc_channel_credentials *
@@ -157,10 +167,13 @@
   return creds;
 }
 
-void grpc_server_credentials_unref(grpc_server_credentials *creds) {
+void grpc_server_credentials_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_server_credentials *creds) {
   if (creds == NULL) return;
   if (gpr_unref(&creds->refcount)) {
-    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    if (creds->vtable->destruct != NULL) {
+      creds->vtable->destruct(exec_ctx, creds);
+    }
     if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
       creds->processor.destroy(creds->processor.state);
     }
@@ -170,16 +183,19 @@
 
 void grpc_server_credentials_release(grpc_server_credentials *creds) {
   GRPC_API_TRACE("grpc_server_credentials_release(creds=%p)", 1, (creds));
-  grpc_server_credentials_unref(creds);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_server_credentials_unref(&exec_ctx, creds);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 grpc_security_status grpc_server_credentials_create_security_connector(
-    grpc_server_credentials *creds, grpc_server_security_connector **sc) {
+    grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds,
+    grpc_server_security_connector **sc) {
   if (creds == NULL || creds->vtable->create_security_connector == NULL) {
     gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
     return GRPC_SECURITY_ERROR;
   }
-  return creds->vtable->create_security_connector(creds, sc);
+  return creds->vtable->create_security_connector(exec_ctx, creds, sc);
 }
 
 void grpc_server_credentials_set_auth_metadata_processor(
@@ -196,8 +212,9 @@
   creds->processor = processor;
 }
 
-static void server_credentials_pointer_arg_destroy(void *p) {
-  grpc_server_credentials_unref(p);
+static void server_credentials_pointer_arg_destroy(grpc_exec_ctx *exec_ctx,
+                                                   void *p) {
+  grpc_server_credentials_unref(exec_ctx, p);
 }
 
 static void *server_credentials_pointer_arg_copy(void *p) {
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index 85b3bc5..3011df6 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -101,12 +101,13 @@
 /* --- grpc_channel_credentials. --- */
 
 typedef struct {
-  void (*destruct)(grpc_channel_credentials *c);
+  void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c);
 
   grpc_security_status (*create_security_connector)(
-      grpc_channel_credentials *c, grpc_call_credentials *call_creds,
-      const char *target, const grpc_channel_args *args,
-      grpc_channel_security_connector **sc, grpc_channel_args **new_args);
+      grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c,
+      grpc_call_credentials *call_creds, const char *target,
+      const grpc_channel_args *args, grpc_channel_security_connector **sc,
+      grpc_channel_args **new_args);
 
   grpc_channel_credentials *(*duplicate_without_call_credentials)(
       grpc_channel_credentials *c);
@@ -120,16 +121,17 @@
 
 grpc_channel_credentials *grpc_channel_credentials_ref(
     grpc_channel_credentials *creds);
-void grpc_channel_credentials_unref(grpc_channel_credentials *creds);
+void grpc_channel_credentials_unref(grpc_exec_ctx *exec_ctx,
+                                    grpc_channel_credentials *creds);
 
 /* Creates a security connector for the channel. May also create new channel
    args for the channel to be used in place of the passed in const args if
    returned non NULL. In that case the caller is responsible for destroying
    new_args after channel creation. */
 grpc_security_status grpc_channel_credentials_create_security_connector(
-    grpc_channel_credentials *creds, const char *target,
-    const grpc_channel_args *args, grpc_channel_security_connector **sc,
-    grpc_channel_args **new_args);
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args);
 
 /* Creates a version of the channel credentials without any attached call
    credentials. This can be used in order to open a channel to a non-trusted
@@ -162,7 +164,8 @@
                                             const char *key, const char *value);
 grpc_credentials_md_store *grpc_credentials_md_store_ref(
     grpc_credentials_md_store *store);
-void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
+void grpc_credentials_md_store_unref(grpc_exec_ctx *exec_ctx,
+                                     grpc_credentials_md_store *store);
 
 /* --- grpc_call_credentials. --- */
 
@@ -172,7 +175,7 @@
     size_t num_md, grpc_credentials_status status, const char *error_details);
 
 typedef struct {
-  void (*destruct)(grpc_call_credentials *c);
+  void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_call_credentials *c);
   void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
                                grpc_call_credentials *c,
                                grpc_polling_entity *pollent,
@@ -188,7 +191,8 @@
 };
 
 grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
-void grpc_call_credentials_unref(grpc_call_credentials *creds);
+void grpc_call_credentials_unref(grpc_exec_ctx *exec_ctx,
+                                 grpc_call_credentials *creds);
 void grpc_call_credentials_get_request_metadata(
     grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
     grpc_polling_entity *pollent, grpc_auth_metadata_context context,
@@ -202,9 +206,10 @@
 /* --- grpc_server_credentials. --- */
 
 typedef struct {
-  void (*destruct)(grpc_server_credentials *c);
+  void (*destruct)(grpc_exec_ctx *exec_ctx, grpc_server_credentials *c);
   grpc_security_status (*create_security_connector)(
-      grpc_server_credentials *c, grpc_server_security_connector **sc);
+      grpc_exec_ctx *exec_ctx, grpc_server_credentials *c,
+      grpc_server_security_connector **sc);
 } grpc_server_credentials_vtable;
 
 struct grpc_server_credentials {
@@ -215,12 +220,14 @@
 };
 
 grpc_security_status grpc_server_credentials_create_security_connector(
-    grpc_server_credentials *creds, grpc_server_security_connector **sc);
+    grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds,
+    grpc_server_security_connector **sc);
 
 grpc_server_credentials *grpc_server_credentials_ref(
     grpc_server_credentials *creds);
 
-void grpc_server_credentials_unref(grpc_server_credentials *creds);
+void grpc_server_credentials_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_server_credentials *creds);
 
 #define GRPC_SERVER_CREDENTIALS_ARG "grpc.server_credentials"
 
@@ -243,6 +250,6 @@
     void *user_data);
 
 void grpc_credentials_metadata_request_destroy(
-    grpc_credentials_metadata_request *r);
+    grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *r);
 
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/credentials_metadata.c b/src/core/lib/security/credentials/credentials_metadata.c
index e6cb567..68da5fb 100644
--- a/src/core/lib/security/credentials/credentials_metadata.c
+++ b/src/core/lib/security/credentials/credentials_metadata.c
@@ -37,6 +37,8 @@
 
 #include <string.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 static void store_ensure_capacity(grpc_credentials_md_store *store) {
   if (store->num_entries == store->allocated) {
     store->allocated = (store->allocated == 0) ? 1 : store->allocated * 2;
@@ -62,8 +64,8 @@
                                    grpc_slice key, grpc_slice value) {
   if (store == NULL) return;
   store_ensure_capacity(store);
-  store->entries[store->num_entries].key = grpc_slice_ref(key);
-  store->entries[store->num_entries].value = grpc_slice_ref(value);
+  store->entries[store->num_entries].key = grpc_slice_ref_internal(key);
+  store->entries[store->num_entries].value = grpc_slice_ref_internal(value);
   store->num_entries++;
 }
 
@@ -85,14 +87,15 @@
   return store;
 }
 
-void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) {
+void grpc_credentials_md_store_unref(grpc_exec_ctx *exec_ctx,
+                                     grpc_credentials_md_store *store) {
   if (store == NULL) return;
   if (gpr_unref(&store->refcount)) {
     if (store->entries != NULL) {
       size_t i;
       for (i = 0; i < store->num_entries; i++) {
-        grpc_slice_unref(store->entries[i].key);
-        grpc_slice_unref(store->entries[i].value);
+        grpc_slice_unref_internal(exec_ctx, store->entries[i].key);
+        grpc_slice_unref_internal(exec_ctx, store->entries[i].value);
       }
       gpr_free(store->entries);
     }
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.c b/src/core/lib/security/credentials/fake/fake_credentials.c
index ea4cb76..a8679d0 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.c
+++ b/src/core/lib/security/credentials/fake/fake_credentials.c
@@ -45,16 +45,18 @@
 /* -- Fake transport security credentials. -- */
 
 static grpc_security_status fake_transport_security_create_security_connector(
-    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c,
+    grpc_call_credentials *call_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
   *sc = grpc_fake_channel_security_connector_create(call_creds);
   return GRPC_SECURITY_OK;
 }
 
 static grpc_security_status
 fake_transport_security_server_create_security_connector(
-    grpc_server_credentials *c, grpc_server_security_connector **sc) {
+    grpc_exec_ctx *exec_ctx, grpc_server_credentials *c,
+    grpc_server_security_connector **sc) {
   *sc = grpc_fake_server_security_connector_create();
   return GRPC_SECURITY_OK;
 }
@@ -89,9 +91,10 @@
 
 /* -- Metadata-only test credentials. -- */
 
-static void md_only_test_destruct(grpc_call_credentials *creds) {
+static void md_only_test_destruct(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_credentials *creds) {
   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
-  grpc_credentials_md_store_unref(c->md_store);
+  grpc_credentials_md_store_unref(exec_ctx, c->md_store);
 }
 
 static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
@@ -101,7 +104,7 @@
   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
   r->cb(exec_ctx, r->user_data, c->md_store->entries, c->md_store->num_entries,
         GRPC_CREDENTIALS_OK, NULL);
-  grpc_credentials_metadata_request_destroy(r);
+  grpc_credentials_metadata_request_destroy(exec_ctx, r);
 }
 
 static void md_only_test_get_request_metadata(
@@ -113,9 +116,10 @@
   if (c->is_async) {
     grpc_credentials_metadata_request *cb_arg =
         grpc_credentials_metadata_request_create(creds, cb, user_data);
-    grpc_executor_push(
-        grpc_closure_create(on_simulated_token_fetch_done, cb_arg),
-        GRPC_ERROR_NONE);
+    grpc_closure_sched(exec_ctx,
+                       grpc_closure_create(on_simulated_token_fetch_done,
+                                           cb_arg, grpc_executor_scheduler),
+                       GRPC_ERROR_NONE);
   } else {
     cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK, NULL);
   }
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.c b/src/core/lib/security/credentials/google_default/google_default_credentials.c
index afe0e3d..d6e1fe3 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.c
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.c
@@ -45,6 +45,7 @@
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/security/credentials/jwt/jwt_credentials.h"
 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/env.h"
 #include "src/core/lib/support/string.h"
@@ -101,11 +102,10 @@
   grpc_pollset_destroy(p);
 }
 
-static int is_stack_running_on_compute_engine(void) {
+static int is_stack_running_on_compute_engine(grpc_exec_ctx *exec_ctx) {
   compute_engine_detector detector;
   grpc_httpcli_request request;
   grpc_httpcli_context context;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_closure destroy_closure;
 
   /* The http call is local. If it takes more than one sec, it is for sure not
@@ -128,13 +128,14 @@
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("google_default_credentials");
   grpc_httpcli_get(
-      &exec_ctx, &context, &detector.pollent, resource_quota, &request,
+      exec_ctx, &context, &detector.pollent, resource_quota, &request,
       gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
-      grpc_closure_create(on_compute_engine_detection_http_response, &detector),
+      grpc_closure_create(on_compute_engine_detection_http_response, &detector,
+                          grpc_schedule_on_exec_ctx),
       &detector.response);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
 
-  grpc_exec_ctx_flush(&exec_ctx);
+  grpc_exec_ctx_flush(exec_ctx);
 
   /* Block until we get the response. This is not ideal but this should only be
      called once for the lifetime of the process by the default credentials. */
@@ -143,7 +144,7 @@
     grpc_pollset_worker *worker = NULL;
     if (!GRPC_LOG_IF_ERROR(
             "pollset_work",
-            grpc_pollset_work(&exec_ctx,
+            grpc_pollset_work(exec_ctx,
                               grpc_polling_entity_pollset(&detector.pollent),
                               &worker, gpr_now(GPR_CLOCK_MONOTONIC),
                               gpr_inf_future(GPR_CLOCK_MONOTONIC)))) {
@@ -155,12 +156,13 @@
 
   grpc_httpcli_context_destroy(&context);
   grpc_closure_init(&destroy_closure, destroy_pollset,
-                    grpc_polling_entity_pollset(&detector.pollent));
-  grpc_pollset_shutdown(&exec_ctx,
+                    grpc_polling_entity_pollset(&detector.pollent),
+                    grpc_schedule_on_exec_ctx);
+  grpc_pollset_shutdown(exec_ctx,
                         grpc_polling_entity_pollset(&detector.pollent),
                         &destroy_closure);
-  grpc_exec_ctx_finish(&exec_ctx);
   g_polling_mu = NULL;
+  grpc_exec_ctx_flush(exec_ctx);
 
   gpr_free(grpc_polling_entity_pollset(&detector.pollent));
   grpc_http_response_destroy(&detector.response);
@@ -170,7 +172,7 @@
 
 /* Takes ownership of creds_path if not NULL. */
 static grpc_error *create_default_creds_from_path(
-    char *creds_path, grpc_call_credentials **creds) {
+    grpc_exec_ctx *exec_ctx, char *creds_path, grpc_call_credentials **creds) {
   grpc_json *json = NULL;
   grpc_auth_json_key key;
   grpc_auth_refresh_token token;
@@ -200,7 +202,7 @@
   if (grpc_auth_json_key_is_valid(&key)) {
     result =
         grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-            key, grpc_max_auth_token_lifetime());
+            exec_ctx, key, grpc_max_auth_token_lifetime());
     if (result == NULL) {
       error = GRPC_ERROR_CREATE(
           "grpc_service_account_jwt_access_credentials_create_from_auth_json_"
@@ -225,7 +227,7 @@
 end:
   GPR_ASSERT((result == NULL) + (error == GRPC_ERROR_NONE) == 1);
   if (creds_path != NULL) gpr_free(creds_path);
-  grpc_slice_unref(creds_data);
+  grpc_slice_unref_internal(exec_ctx, creds_data);
   if (json != NULL) grpc_json_destroy(json);
   *creds = result;
   return error;
@@ -236,6 +238,7 @@
   grpc_call_credentials *call_creds = NULL;
   grpc_error *error = GRPC_ERROR_CREATE("Failed to create Google credentials");
   grpc_error *err;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
 
@@ -250,20 +253,22 @@
 
   /* First, try the environment variable. */
   err = create_default_creds_from_path(
-      gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
+      &exec_ctx, gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR), &call_creds);
   if (err == GRPC_ERROR_NONE) goto end;
   error = grpc_error_add_child(error, err);
 
   /* Then the well-known file. */
   err = create_default_creds_from_path(
-      grpc_get_well_known_google_credentials_file_path(), &call_creds);
+      &exec_ctx, grpc_get_well_known_google_credentials_file_path(),
+      &call_creds);
   if (err == GRPC_ERROR_NONE) goto end;
   error = grpc_error_add_child(error, err);
 
   /* At last try to see if we're on compute engine (do the detection only once
      since it requires a network test). */
   if (!compute_engine_detection_done) {
-    int need_compute_engine_creds = is_stack_running_on_compute_engine();
+    int need_compute_engine_creds =
+        is_stack_running_on_compute_engine(&exec_ctx);
     compute_engine_detection_done = 1;
     if (need_compute_engine_creds) {
       call_creds = grpc_google_compute_engine_credentials_create(NULL);
@@ -286,8 +291,8 @@
           grpc_composite_channel_credentials_create(ssl_creds, call_creds,
                                                     NULL));
       GPR_ASSERT(default_credentials != NULL);
-      grpc_channel_credentials_unref(ssl_creds);
-      grpc_call_credentials_unref(call_creds);
+      grpc_channel_credentials_unref(&exec_ctx, ssl_creds);
+      grpc_call_credentials_unref(&exec_ctx, call_creds);
       result = default_credentials;
     } else {
       gpr_log(GPR_ERROR, "Could not create google default credentials.");
@@ -299,18 +304,21 @@
   } else {
     GRPC_ERROR_UNREF(error);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   return result;
 }
 
 void grpc_flush_cached_google_default_credentials(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   gpr_once_init(&g_once, init_default_credentials);
   gpr_mu_lock(&g_state_mu);
   if (default_credentials != NULL) {
-    grpc_channel_credentials_unref(default_credentials);
+    grpc_channel_credentials_unref(&exec_ctx, default_credentials);
     default_credentials = NULL;
   }
   compute_engine_detection_done = 0;
   gpr_mu_unlock(&g_state_mu);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 /* -- Well known credentials path. -- */
diff --git a/src/core/lib/security/credentials/iam/iam_credentials.c b/src/core/lib/security/credentials/iam/iam_credentials.c
index 370a384..abd69a9 100644
--- a/src/core/lib/security/credentials/iam/iam_credentials.c
+++ b/src/core/lib/security/credentials/iam/iam_credentials.c
@@ -42,9 +42,10 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-static void iam_destruct(grpc_call_credentials *creds) {
+static void iam_destruct(grpc_exec_ctx *exec_ctx,
+                         grpc_call_credentials *creds) {
   grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
-  grpc_credentials_md_store_unref(c->iam_md);
+  grpc_credentials_md_store_unref(exec_ctx, c->iam_md);
 }
 
 static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c
index 3daf0f4..616be64 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.c
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c
@@ -42,9 +42,10 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
-static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
+static void jwt_reset_cache(grpc_exec_ctx *exec_ctx,
+                            grpc_service_account_jwt_access_credentials *c) {
   if (c->cached.jwt_md != NULL) {
-    grpc_credentials_md_store_unref(c->cached.jwt_md);
+    grpc_credentials_md_store_unref(exec_ctx, c->cached.jwt_md);
     c->cached.jwt_md = NULL;
   }
   if (c->cached.service_url != NULL) {
@@ -54,11 +55,12 @@
   c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
 }
 
-static void jwt_destruct(grpc_call_credentials *creds) {
+static void jwt_destruct(grpc_exec_ctx *exec_ctx,
+                         grpc_call_credentials *creds) {
   grpc_service_account_jwt_access_credentials *c =
       (grpc_service_account_jwt_access_credentials *)creds;
   grpc_auth_json_key_destruct(&c->key);
-  jwt_reset_cache(c);
+  jwt_reset_cache(exec_ctx, c);
   gpr_mu_destroy(&c->cache_mu);
 }
 
@@ -92,7 +94,7 @@
     char *jwt = NULL;
     /* Generate a new jwt. */
     gpr_mu_lock(&c->cache_mu);
-    jwt_reset_cache(c);
+    jwt_reset_cache(exec_ctx, c);
     jwt = grpc_jwt_encode_and_sign(&c->key, context.service_url,
                                    c->jwt_lifetime, NULL);
     if (jwt != NULL) {
@@ -114,7 +116,7 @@
   if (jwt_md != NULL) {
     cb(exec_ctx, user_data, jwt_md->entries, jwt_md->num_entries,
        GRPC_CREDENTIALS_OK, NULL);
-    grpc_credentials_md_store_unref(jwt_md);
+    grpc_credentials_md_store_unref(exec_ctx, jwt_md);
   } else {
     cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_ERROR,
        "Could not generate JWT.");
@@ -126,7 +128,8 @@
 
 grpc_call_credentials *
 grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-    grpc_auth_json_key key, gpr_timespec token_lifetime) {
+    grpc_exec_ctx *exec_ctx, grpc_auth_json_key key,
+    gpr_timespec token_lifetime) {
   grpc_service_account_jwt_access_credentials *c;
   if (!grpc_auth_json_key_is_valid(&key)) {
     gpr_log(GPR_ERROR, "Invalid input for jwt credentials creation");
@@ -140,7 +143,7 @@
   c->key = key;
   c->jwt_lifetime = token_lifetime;
   gpr_mu_init(&c->cache_mu);
-  jwt_reset_cache(c);
+  jwt_reset_cache(exec_ctx, c);
   return &c->base;
 }
 
@@ -183,6 +186,11 @@
     gpr_free(clean_json);
   }
   GPR_ASSERT(reserved == NULL);
-  return grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-      grpc_auth_json_key_create_from_string(json_key), token_lifetime);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_call_credentials *creds =
+      grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
+          &exec_ctx, grpc_auth_json_key_create_from_string(json_key),
+          token_lifetime);
+  grpc_exec_ctx_finish(&exec_ctx);
+  return creds;
 }
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.h b/src/core/lib/security/credentials/jwt/jwt_credentials.h
index d572606..39b7aea 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.h
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.h
@@ -57,6 +57,7 @@
 // Takes ownership of the key.
 grpc_call_credentials *
 grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-    grpc_auth_json_key key, gpr_timespec token_lifetime);
+    grpc_exec_ctx *exec_ctx, grpc_auth_json_key key,
+    gpr_timespec token_lifetime);
 
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c
index 42bd89d..2270be8 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.c
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c
@@ -36,11 +36,6 @@
 #include <limits.h>
 #include <string.h>
 
-#include "src/core/lib/http/httpcli.h"
-#include "src/core/lib/iomgr/polling_entity.h"
-#include "src/core/lib/security/util/b64.h"
-#include "src/core/lib/tsi/ssl_types.h"
-
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
@@ -48,6 +43,13 @@
 #include <grpc/support/useful.h>
 #include <openssl/pem.h>
 
+#include "src/core/lib/http/httpcli.h"
+#include "src/core/lib/iomgr/polling_entity.h"
+#include "src/core/lib/security/util/b64.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/tsi/ssl_types.h"
+
 /* --- Utils. --- */
 
 const char *grpc_jwt_verifier_status_to_string(
@@ -84,11 +86,12 @@
   }
 }
 
-static grpc_json *parse_json_part_from_jwt(const char *str, size_t len,
+static grpc_json *parse_json_part_from_jwt(grpc_exec_ctx *exec_ctx,
+                                           const char *str, size_t len,
                                            grpc_slice *buffer) {
   grpc_json *json;
 
-  *buffer = grpc_base64_decode_with_len(str, len, 1);
+  *buffer = grpc_base64_decode_with_len(exec_ctx, str, len, 1);
   if (GRPC_SLICE_IS_EMPTY(*buffer)) {
     gpr_log(GPR_ERROR, "Invalid base64.");
     return NULL;
@@ -96,7 +99,7 @@
   json = grpc_json_parse_string_with_len((char *)GRPC_SLICE_START_PTR(*buffer),
                                          GRPC_SLICE_LENGTH(*buffer));
   if (json == NULL) {
-    grpc_slice_unref(*buffer);
+    grpc_slice_unref_internal(exec_ctx, *buffer);
     gpr_log(GPR_ERROR, "JSON parsing error.");
   }
   return json;
@@ -132,13 +135,14 @@
   grpc_slice buffer;
 } jose_header;
 
-static void jose_header_destroy(jose_header *h) {
-  grpc_slice_unref(h->buffer);
+static void jose_header_destroy(grpc_exec_ctx *exec_ctx, jose_header *h) {
+  grpc_slice_unref_internal(exec_ctx, h->buffer);
   gpr_free(h);
 }
 
 /* Takes ownership of json and buffer. */
-static jose_header *jose_header_from_json(grpc_json *json, grpc_slice buffer) {
+static jose_header *jose_header_from_json(grpc_exec_ctx *exec_ctx,
+                                          grpc_json *json, grpc_slice buffer) {
   grpc_json *cur;
   jose_header *h = gpr_malloc(sizeof(jose_header));
   memset(h, 0, sizeof(jose_header));
@@ -173,7 +177,7 @@
 
 error:
   grpc_json_destroy(json);
-  jose_header_destroy(h);
+  jose_header_destroy(exec_ctx, h);
   return NULL;
 }
 
@@ -193,9 +197,9 @@
   grpc_slice buffer;
 };
 
-void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) {
+void grpc_jwt_claims_destroy(grpc_exec_ctx *exec_ctx, grpc_jwt_claims *claims) {
   grpc_json_destroy(claims->json);
-  grpc_slice_unref(claims->buffer);
+  grpc_slice_unref_internal(exec_ctx, claims->buffer);
   gpr_free(claims);
 }
 
@@ -240,7 +244,8 @@
 }
 
 /* Takes ownership of json and buffer even in case of failure. */
-grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer) {
+grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_exec_ctx *exec_ctx,
+                                           grpc_json *json, grpc_slice buffer) {
   grpc_json *cur;
   grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims));
   memset(claims, 0, sizeof(grpc_jwt_claims));
@@ -281,7 +286,7 @@
   return claims;
 
 error:
-  grpc_jwt_claims_destroy(claims);
+  grpc_jwt_claims_destroy(exec_ctx, claims);
   return NULL;
 }
 
@@ -305,6 +310,17 @@
     return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
   }
 
+  /* This should be probably up to the upper layer to decide but let's harcode
+     the 99% use case here for email issuers, where the JWT must be self
+     issued. */
+  if (grpc_jwt_issuer_email_domain(claims->iss) != NULL &&
+      claims->sub != NULL && strcmp(claims->iss, claims->sub) != 0) {
+    gpr_log(GPR_ERROR,
+            "Email issuer (%s) cannot assert another subject (%s) than itself.",
+            claims->iss, claims->sub);
+    return GRPC_JWT_VERIFIER_BAD_SUBJECT;
+  }
+
   if (audience == NULL) {
     audience_ok = claims->aud == NULL;
   } else {
@@ -362,12 +378,12 @@
   return ctx;
 }
 
-void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) {
+void verifier_cb_ctx_destroy(grpc_exec_ctx *exec_ctx, verifier_cb_ctx *ctx) {
   if (ctx->audience != NULL) gpr_free(ctx->audience);
-  if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims);
-  grpc_slice_unref(ctx->signature);
-  grpc_slice_unref(ctx->signed_data);
-  jose_header_destroy(ctx->header);
+  if (ctx->claims != NULL) grpc_jwt_claims_destroy(exec_ctx, ctx->claims);
+  grpc_slice_unref_internal(exec_ctx, ctx->signature);
+  grpc_slice_unref_internal(exec_ctx, ctx->signed_data);
+  jose_header_destroy(exec_ctx, ctx->header);
   for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) {
     grpc_http_response_destroy(&ctx->responses[i]);
   }
@@ -447,23 +463,24 @@
   return result;
 }
 
-static BIGNUM *bignum_from_base64(const char *b64) {
+static BIGNUM *bignum_from_base64(grpc_exec_ctx *exec_ctx, const char *b64) {
   BIGNUM *result = NULL;
   grpc_slice bin;
 
   if (b64 == NULL) return NULL;
-  bin = grpc_base64_decode(b64, 1);
+  bin = grpc_base64_decode(exec_ctx, b64, 1);
   if (GRPC_SLICE_IS_EMPTY(bin)) {
     gpr_log(GPR_ERROR, "Invalid base64 for big num.");
     return NULL;
   }
   result = BN_bin2bn(GRPC_SLICE_START_PTR(bin),
                      TSI_SIZE_AS_SIZE(GRPC_SLICE_LENGTH(bin)), NULL);
-  grpc_slice_unref(bin);
+  grpc_slice_unref_internal(exec_ctx, bin);
   return result;
 }
 
-static EVP_PKEY *pkey_from_jwk(const grpc_json *json, const char *kty) {
+static EVP_PKEY *pkey_from_jwk(grpc_exec_ctx *exec_ctx, const grpc_json *json,
+                               const char *kty) {
   const grpc_json *key_prop;
   RSA *rsa = NULL;
   EVP_PKEY *result = NULL;
@@ -480,10 +497,12 @@
   }
   for (key_prop = json->child; key_prop != NULL; key_prop = key_prop->next) {
     if (strcmp(key_prop->key, "n") == 0) {
-      rsa->n = bignum_from_base64(validate_string_field(key_prop, "n"));
+      rsa->n =
+          bignum_from_base64(exec_ctx, validate_string_field(key_prop, "n"));
       if (rsa->n == NULL) goto end;
     } else if (strcmp(key_prop->key, "e") == 0) {
-      rsa->e = bignum_from_base64(validate_string_field(key_prop, "e"));
+      rsa->e =
+          bignum_from_base64(exec_ctx, validate_string_field(key_prop, "e"));
       if (rsa->e == NULL) goto end;
     }
   }
@@ -499,7 +518,8 @@
   return result;
 }
 
-static EVP_PKEY *find_verification_key(const grpc_json *json,
+static EVP_PKEY *find_verification_key(grpc_exec_ctx *exec_ctx,
+                                       const grpc_json *json,
                                        const char *header_alg,
                                        const char *header_kid) {
   const grpc_json *jkey;
@@ -543,7 +563,7 @@
     }
     if (alg != NULL && kid != NULL && kty != NULL &&
         strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) {
-      return pkey_from_jwk(jkey, kty);
+      return pkey_from_jwk(exec_ctx, jkey, kty);
     }
   }
   gpr_log(GPR_ERROR,
@@ -597,7 +617,7 @@
     goto end;
   }
   verification_key =
-      find_verification_key(json, ctx->header->alg, ctx->header->kid);
+      find_verification_key(exec_ctx, json, ctx->header->alg, ctx->header->kid);
   if (verification_key == NULL) {
     gpr_log(GPR_ERROR, "Could not find verification key with kid %s.",
             ctx->header->kid);
@@ -621,8 +641,8 @@
 end:
   if (json != NULL) grpc_json_destroy(json);
   if (verification_key != NULL) EVP_PKEY_free(verification_key);
-  ctx->user_cb(ctx->user_data, status, claims);
-  verifier_cb_ctx_destroy(ctx);
+  ctx->user_cb(exec_ctx, ctx->user_data, status, claims);
+  verifier_cb_ctx_destroy(exec_ctx, ctx);
 }
 
 static void on_openid_config_retrieved(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -665,17 +685,18 @@
   grpc_httpcli_get(
       exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
       gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
-      grpc_closure_create(on_keys_retrieved, ctx),
+      grpc_closure_create(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx),
       &ctx->responses[HTTP_RESPONSE_KEYS]);
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   grpc_json_destroy(json);
   gpr_free(req.host);
   return;
 
 error:
   if (json != NULL) grpc_json_destroy(json);
-  ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL);
-  verifier_cb_ctx_destroy(ctx);
+  ctx->user_cb(exec_ctx, ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR,
+               NULL);
+  verifier_cb_ctx_destroy(exec_ctx, ctx);
 }
 
 static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v,
@@ -705,10 +726,26 @@
   GPR_ASSERT(v->num_mappings <= v->allocated_mappings);
 }
 
+/* Very non-sophisticated way to detect an email address. Should be good
+   enough for now... */
+const char *grpc_jwt_issuer_email_domain(const char *issuer) {
+  const char *at_sign = strchr(issuer, '@');
+  if (at_sign == NULL) return NULL;
+  const char *email_domain = at_sign + 1;
+  if (*email_domain == '\0') return NULL;
+  const char *dot = strrchr(email_domain, '.');
+  if (dot == NULL || dot == email_domain) return email_domain;
+  GPR_ASSERT(dot > email_domain);
+  /* There may be a subdomain, we just want the domain. */
+  dot = gpr_memrchr(email_domain, '.', (size_t)(dot - email_domain));
+  if (dot == NULL) return email_domain;
+  return dot + 1;
+}
+
 /* Takes ownership of ctx. */
 static void retrieve_key_and_verify(grpc_exec_ctx *exec_ctx,
                                     verifier_cb_ctx *ctx) {
-  const char *at_sign;
+  const char *email_domain;
   grpc_closure *http_cb;
   char *path_prefix = NULL;
   const char *iss;
@@ -733,13 +770,9 @@
      Nobody seems to implement the account/email/webfinger part 2. of the spec
      so we will rely instead on email/url mappings if we detect such an issuer.
      Part 4, on the other hand is implemented by both google and salesforce. */
-
-  /* Very non-sophisticated way to detect an email address. Should be good
-     enough for now... */
-  at_sign = strchr(iss, '@');
-  if (at_sign != NULL) {
+  email_domain = grpc_jwt_issuer_email_domain(iss);
+  if (email_domain != NULL) {
     email_key_mapping *mapping;
-    const char *email_domain = at_sign + 1;
     GPR_ASSERT(ctx->verifier != NULL);
     mapping = verifier_get_mapping(ctx->verifier, email_domain);
     if (mapping == NULL) {
@@ -754,7 +787,8 @@
       *(path_prefix++) = '\0';
       gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss);
     }
-    http_cb = grpc_closure_create(on_keys_retrieved, ctx);
+    http_cb =
+        grpc_closure_create(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx);
     rsp_idx = HTTP_RESPONSE_KEYS;
   } else {
     req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss);
@@ -766,7 +800,8 @@
       gpr_asprintf(&req.http.path, "/%s%s", path_prefix,
                    GRPC_OPENID_CONFIG_URL_SUFFIX);
     }
-    http_cb = grpc_closure_create(on_openid_config_retrieved, ctx);
+    http_cb = grpc_closure_create(on_openid_config_retrieved, ctx,
+                                  grpc_schedule_on_exec_ctx);
     rsp_idx = HTTP_RESPONSE_OPENID;
   }
 
@@ -779,14 +814,15 @@
       exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req,
       gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
       http_cb, &ctx->responses[rsp_idx]);
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   gpr_free(req.host);
   gpr_free(req.http.path);
   return;
 
 error:
-  ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, NULL);
-  verifier_cb_ctx_destroy(ctx);
+  ctx->user_cb(exec_ctx, ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR,
+               NULL);
+  verifier_cb_ctx_destroy(exec_ctx, ctx);
 }
 
 void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx,
@@ -808,22 +844,24 @@
   GPR_ASSERT(verifier != NULL && jwt != NULL && audience != NULL && cb != NULL);
   dot = strchr(cur, '.');
   if (dot == NULL) goto error;
-  json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer);
+  json = parse_json_part_from_jwt(exec_ctx, cur, (size_t)(dot - cur),
+                                  &header_buffer);
   if (json == NULL) goto error;
-  header = jose_header_from_json(json, header_buffer);
+  header = jose_header_from_json(exec_ctx, json, header_buffer);
   if (header == NULL) goto error;
 
   cur = dot + 1;
   dot = strchr(cur, '.');
   if (dot == NULL) goto error;
-  json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer);
+  json = parse_json_part_from_jwt(exec_ctx, cur, (size_t)(dot - cur),
+                                  &claims_buffer);
   if (json == NULL) goto error;
-  claims = grpc_jwt_claims_from_json(json, claims_buffer);
+  claims = grpc_jwt_claims_from_json(exec_ctx, json, claims_buffer);
   if (claims == NULL) goto error;
 
   signed_jwt_len = (size_t)(dot - jwt);
   cur = dot + 1;
-  signature = grpc_base64_decode(cur, 1);
+  signature = grpc_base64_decode(exec_ctx, cur, 1);
   if (GRPC_SLICE_IS_EMPTY(signature)) goto error;
   retrieve_key_and_verify(
       exec_ctx,
@@ -832,9 +870,9 @@
   return;
 
 error:
-  if (header != NULL) jose_header_destroy(header);
-  if (claims != NULL) grpc_jwt_claims_destroy(claims);
-  cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL);
+  if (header != NULL) jose_header_destroy(exec_ctx, header);
+  if (claims != NULL) grpc_jwt_claims_destroy(exec_ctx, claims);
+  cb(exec_ctx, user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, NULL);
 }
 
 grpc_jwt_verifier *grpc_jwt_verifier_create(
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.h b/src/core/lib/security/credentials/jwt/jwt_verifier.h
index f09f9d5..4fa320a 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.h
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h
@@ -43,8 +43,7 @@
 /* --- Constants. --- */
 
 #define GRPC_OPENID_CONFIG_URL_SUFFIX "/.well-known/openid-configuration"
-#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN \
-  "developer.gserviceaccount.com"
+#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN "gserviceaccount.com"
 #define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \
   "www.googleapis.com/robot/v1/metadata/x509"
 
@@ -57,6 +56,7 @@
   GRPC_JWT_VERIFIER_BAD_AUDIENCE,
   GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR,
   GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE,
+  GRPC_JWT_VERIFIER_BAD_SUBJECT,
   GRPC_JWT_VERIFIER_GENERIC_ERROR
 } grpc_jwt_verifier_status;
 
@@ -66,7 +66,7 @@
 
 typedef struct grpc_jwt_claims grpc_jwt_claims;
 
-void grpc_jwt_claims_destroy(grpc_jwt_claims *claims);
+void grpc_jwt_claims_destroy(grpc_exec_ctx *exec_ctx, grpc_jwt_claims *claims);
 
 /* Returns the whole JSON tree of the claims. */
 const grpc_json *grpc_jwt_claims_json(const grpc_jwt_claims *claims);
@@ -115,7 +115,8 @@
    is done (maybe in another thread).
    It is the responsibility of the callee to call grpc_jwt_claims_destroy on
    the claims. */
-typedef void (*grpc_jwt_verification_done_cb)(void *user_data,
+typedef void (*grpc_jwt_verification_done_cb)(grpc_exec_ctx *exec_ctx,
+                                              void *user_data,
                                               grpc_jwt_verifier_status status,
                                               grpc_jwt_claims *claims);
 
@@ -129,8 +130,10 @@
 
 /* --- TESTING ONLY exposed functions. --- */
 
-grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer);
+grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_exec_ctx *exec_ctx,
+                                           grpc_json *json, grpc_slice buffer);
 grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims,
                                                const char *audience);
+const char *grpc_jwt_issuer_email_domain(const char *issuer);
 
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_VERIFIER_H */
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
index b3625b2..1b0e43a 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c
@@ -118,18 +118,19 @@
 // Oauth2 Token Fetcher credentials.
 //
 
-static void oauth2_token_fetcher_destruct(grpc_call_credentials *creds) {
+static void oauth2_token_fetcher_destruct(grpc_exec_ctx *exec_ctx,
+                                          grpc_call_credentials *creds) {
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
-  grpc_credentials_md_store_unref(c->access_token_md);
+  grpc_credentials_md_store_unref(exec_ctx, c->access_token_md);
   gpr_mu_destroy(&c->mu);
   grpc_httpcli_context_destroy(&c->httpcli_context);
 }
 
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
-    const grpc_http_response *response, grpc_credentials_md_store **token_md,
-    gpr_timespec *token_lifetime) {
+    grpc_exec_ctx *exec_ctx, const grpc_http_response *response,
+    grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime) {
   char *null_terminated_body = NULL;
   char *new_access_token = NULL;
   grpc_credentials_status status = GRPC_CREDENTIALS_OK;
@@ -198,7 +199,7 @@
     token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
     token_lifetime->tv_nsec = 0;
     token_lifetime->clock_type = GPR_TIMESPAN;
-    if (*token_md != NULL) grpc_credentials_md_store_unref(*token_md);
+    if (*token_md != NULL) grpc_credentials_md_store_unref(exec_ctx, *token_md);
     *token_md = grpc_credentials_md_store_create(1);
     grpc_credentials_md_store_add_cstrings(
         *token_md, GRPC_AUTHORIZATION_METADATA_KEY, new_access_token);
@@ -207,7 +208,7 @@
 
 end:
   if (status != GRPC_CREDENTIALS_OK && (*token_md != NULL)) {
-    grpc_credentials_md_store_unref(*token_md);
+    grpc_credentials_md_store_unref(exec_ctx, *token_md);
     *token_md = NULL;
   }
   if (null_terminated_body != NULL) gpr_free(null_terminated_body);
@@ -230,7 +231,7 @@
 
   gpr_mu_lock(&c->mu);
   status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
-      &r->response, &c->access_token_md, &token_lifetime);
+      exec_ctx, &r->response, &c->access_token_md, &token_lifetime);
   if (status == GRPC_CREDENTIALS_OK) {
     c->token_expiration =
         gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime);
@@ -242,7 +243,7 @@
           "Error occured when fetching oauth2 token.");
   }
   gpr_mu_unlock(&c->mu);
-  grpc_credentials_metadata_request_destroy(r);
+  grpc_credentials_metadata_request_destroy(exec_ctx, r);
 }
 
 static void oauth2_token_fetcher_get_request_metadata(
@@ -268,7 +269,7 @@
   if (cached_access_token_md != NULL) {
     cb(exec_ctx, user_data, cached_access_token_md->entries,
        cached_access_token_md->num_entries, GRPC_CREDENTIALS_OK, NULL);
-    grpc_credentials_md_store_unref(cached_access_token_md);
+    grpc_credentials_md_store_unref(exec_ctx, cached_access_token_md);
   } else {
     c->fetch_func(
         exec_ctx,
@@ -312,10 +313,12 @@
      extreme memory pressure. */
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("oauth2_credentials");
-  grpc_httpcli_get(exec_ctx, httpcli_context, pollent, resource_quota, &request,
-                   deadline, grpc_closure_create(response_cb, metadata_req),
-                   &metadata_req->response);
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_httpcli_get(
+      exec_ctx, httpcli_context, pollent, resource_quota, &request, deadline,
+      grpc_closure_create(response_cb, metadata_req, grpc_schedule_on_exec_ctx),
+
+      &metadata_req->response);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
 }
 
 grpc_call_credentials *grpc_google_compute_engine_credentials_create(
@@ -334,11 +337,12 @@
 // Google Refresh Token credentials.
 //
 
-static void refresh_token_destruct(grpc_call_credentials *creds) {
+static void refresh_token_destruct(grpc_exec_ctx *exec_ctx,
+                                   grpc_call_credentials *creds) {
   grpc_google_refresh_token_credentials *c =
       (grpc_google_refresh_token_credentials *)creds;
   grpc_auth_refresh_token_destruct(&c->refresh_token);
-  oauth2_token_fetcher_destruct(&c->base.base);
+  oauth2_token_fetcher_destruct(exec_ctx, &c->base.base);
 }
 
 static grpc_call_credentials_vtable refresh_token_vtable = {
@@ -368,11 +372,12 @@
      extreme memory pressure. */
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("oauth2_credentials_refresh");
-  grpc_httpcli_post(exec_ctx, httpcli_context, pollent, resource_quota,
-                    &request, body, strlen(body), deadline,
-                    grpc_closure_create(response_cb, metadata_req),
-                    &metadata_req->response);
-  grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+  grpc_httpcli_post(
+      exec_ctx, httpcli_context, pollent, resource_quota, &request, body,
+      strlen(body), deadline,
+      grpc_closure_create(response_cb, metadata_req, grpc_schedule_on_exec_ctx),
+      &metadata_req->response);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   gpr_free(body);
 }
 
@@ -424,9 +429,10 @@
 // Oauth2 Access Token credentials.
 //
 
-static void access_token_destruct(grpc_call_credentials *creds) {
+static void access_token_destruct(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_credentials *creds) {
   grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
-  grpc_credentials_md_store_unref(c->access_token_md);
+  grpc_credentials_md_store_unref(exec_ctx, c->access_token_md);
 }
 
 static void access_token_get_request_metadata(
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
index 7f6f205..2d7c02c 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -103,7 +103,7 @@
 // Exposed for testing only.
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
-    const struct grpc_http_response *response,
+    grpc_exec_ctx *exec_ctx, const struct grpc_http_response *response,
     grpc_credentials_md_store **token_md, gpr_timespec *token_lifetime);
 
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c
index 5d95009..f90d7dc 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.c
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c
@@ -35,20 +35,22 @@
 
 #include <string.h>
 
-#include "src/core/lib/surface/api_trace.h"
-
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/surface/api_trace.h"
+
 typedef struct {
   void *user_data;
   grpc_credentials_metadata_cb cb;
 } grpc_metadata_plugin_request;
 
-static void plugin_destruct(grpc_call_credentials *creds) {
+static void plugin_destruct(grpc_exec_ctx *exec_ctx,
+                            grpc_call_credentials *creds) {
   grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
   if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
     c->plugin.destroy(c->plugin.state);
@@ -100,8 +102,8 @@
       r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK,
             NULL);
       for (i = 0; i < num_md; i++) {
-        grpc_slice_unref(md_array[i].key);
-        grpc_slice_unref(md_array[i].value);
+        grpc_slice_unref_internal(&exec_ctx, md_array[i].key);
+        grpc_slice_unref_internal(&exec_ctx, md_array[i].value);
       }
       gpr_free(md_array);
     } else if (num_md == 0) {
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.c b/src/core/lib/security/credentials/ssl/ssl_credentials.c
index 0dc1fcc..4eebb7d 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.c
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.c
@@ -57,7 +57,8 @@
 // SSL Channel Credentials.
 //
 
-static void ssl_destruct(grpc_channel_credentials *creds) {
+static void ssl_destruct(grpc_exec_ctx *exec_ctx,
+                         grpc_channel_credentials *creds) {
   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
   if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
@@ -65,9 +66,10 @@
 }
 
 static grpc_security_status ssl_create_security_connector(
-    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *creds,
+    grpc_call_credentials *call_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
   grpc_security_status status = GRPC_SECURITY_OK;
   size_t i = 0;
@@ -83,7 +85,7 @@
     }
   }
   status = grpc_ssl_channel_security_connector_create(
-      call_creds, &c->config, target, overridden_target_name, sc);
+      exec_ctx, call_creds, &c->config, target, overridden_target_name, sc);
   if (status != GRPC_SECURITY_OK) {
     return status;
   }
@@ -138,7 +140,8 @@
 // SSL Server Credentials.
 //
 
-static void ssl_server_destruct(grpc_server_credentials *creds) {
+static void ssl_server_destruct(grpc_exec_ctx *exec_ctx,
+                                grpc_server_credentials *creds) {
   grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
   size_t i;
   for (i = 0; i < c->config.num_key_cert_pairs; i++) {
@@ -161,9 +164,10 @@
 }
 
 static grpc_security_status ssl_server_create_security_connector(
-    grpc_server_credentials *creds, grpc_server_security_connector **sc) {
+    grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds,
+    grpc_server_security_connector **sc) {
   grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
-  return grpc_ssl_server_security_connector_create(&c->config, sc);
+  return grpc_ssl_server_security_connector_create(exec_ctx, &c->config, sc);
 }
 
 static grpc_server_credentials_vtable ssl_server_vtable = {
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index 053bf59..b7f6fd2 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -44,6 +44,7 @@
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/transport/static_metadata.h"
@@ -93,7 +94,8 @@
   call_data *calld = elem->call_data;
   gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg);
   grpc_slice error_slice = grpc_slice_from_copied_string(error_msg);
-  grpc_transport_stream_op_add_close(&calld->op, status, &error_slice);
+  grpc_transport_stream_op_add_close(exec_ctx, &calld->op, status,
+                                     &error_slice);
   grpc_call_next_op(exec_ctx, elem, &calld->op);
 }
 
@@ -121,8 +123,9 @@
   for (i = 0; i < num_md; i++) {
     grpc_metadata_batch_add_tail(
         mdb, &calld->md_links[i],
-        grpc_mdelem_from_slices(grpc_slice_ref(md_elems[i].key),
-                                grpc_slice_ref(md_elems[i].value)));
+        grpc_mdelem_from_slices(exec_ctx,
+                                grpc_slice_ref_internal(md_elems[i].key),
+                                grpc_slice_ref_internal(md_elems[i].value)));
   }
   grpc_call_next_op(exec_ctx, elem, op);
 }
@@ -248,10 +251,10 @@
       /* Pointer comparison is OK for md_elems created from the same context.
        */
       if (md->key == GRPC_MDSTR_AUTHORITY) {
-        if (calld->host != NULL) GRPC_MDSTR_UNREF(calld->host);
+        if (calld->host != NULL) GRPC_MDSTR_UNREF(exec_ctx, calld->host);
         calld->host = GRPC_MDSTR_REF(md->value);
       } else if (md->key == GRPC_MDSTR_PATH) {
-        if (calld->method != NULL) GRPC_MDSTR_UNREF(calld->method);
+        if (calld->method != NULL) GRPC_MDSTR_UNREF(exec_ctx, calld->method);
         calld->method = GRPC_MDSTR_REF(md->value);
       }
     }
@@ -292,20 +295,20 @@
                               const grpc_call_final_info *final_info,
                               void *ignored) {
   call_data *calld = elem->call_data;
-  grpc_call_credentials_unref(calld->creds);
+  grpc_call_credentials_unref(exec_ctx, calld->creds);
   if (calld->host != NULL) {
-    GRPC_MDSTR_UNREF(calld->host);
+    GRPC_MDSTR_UNREF(exec_ctx, calld->host);
   }
   if (calld->method != NULL) {
-    GRPC_MDSTR_UNREF(calld->method);
+    GRPC_MDSTR_UNREF(exec_ctx, calld->method);
   }
   reset_auth_metadata_context(&calld->auth_md_context);
 }
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   grpc_security_connector *sc =
       grpc_find_security_connector_in_args(args->channel_args);
   grpc_auth_context *auth_context =
@@ -327,6 +330,7 @@
           sc, "client_auth_filter");
   chand->auth_context =
       GRPC_AUTH_CONTEXT_REF(auth_context, "client_auth_filter");
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel data */
@@ -336,7 +340,7 @@
   channel_data *chand = elem->channel_data;
   grpc_channel_security_connector *sc = chand->security_connector;
   if (sc != NULL) {
-    GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "client_auth_filter");
+    GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, &sc->base, "client_auth_filter");
   }
   GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter");
 }
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 1b27841..18a7a6f 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -46,6 +46,7 @@
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
 #include "src/core/lib/security/transport/tsi_error.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/tsi/transport_security_interface.h"
@@ -80,11 +81,11 @@
   secure_endpoint *ep = secure_ep;
   grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep);
   tsi_frame_protector_destroy(ep->protector);
-  grpc_slice_buffer_destroy(&ep->leftover_bytes);
-  grpc_slice_unref(ep->read_staging_buffer);
-  grpc_slice_unref(ep->write_staging_buffer);
-  grpc_slice_buffer_destroy(&ep->output_buffer);
-  grpc_slice_buffer_destroy(&ep->source_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &ep->leftover_bytes);
+  grpc_slice_unref_internal(exec_ctx, ep->read_staging_buffer);
+  grpc_slice_unref_internal(exec_ctx, ep->write_staging_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &ep->output_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &ep->source_buffer);
   gpr_mu_destroy(&ep->protector_mu);
   gpr_free(ep);
 }
@@ -146,7 +147,7 @@
     }
   }
   ep->read_buffer = NULL;
-  grpc_exec_ctx_sched(exec_ctx, ep->read_cb, error, NULL);
+  grpc_closure_sched(exec_ctx, ep->read_cb, error);
   SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read");
 }
 
@@ -160,7 +161,7 @@
   uint8_t *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer);
 
   if (error != GRPC_ERROR_NONE) {
-    grpc_slice_buffer_reset_and_unref(ep->read_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer);
     call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING(
                                    "Secure read failed", &error, 1));
     return;
@@ -215,10 +216,10 @@
 
   /* TODO(yangg) experiment with moving this block after read_cb to see if it
      helps latency */
-  grpc_slice_buffer_reset_and_unref(&ep->source_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->source_buffer);
 
   if (result != TSI_OK) {
-    grpc_slice_buffer_reset_and_unref(ep->read_buffer);
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer);
     call_read_cb(exec_ctx, ep, grpc_set_tsi_error_result(
                                    GRPC_ERROR_CREATE("Unwrap failed"), result));
     return;
@@ -232,7 +233,7 @@
   secure_endpoint *ep = (secure_endpoint *)secure_ep;
   ep->read_cb = cb;
   ep->read_buffer = slices;
-  grpc_slice_buffer_reset_and_unref(ep->read_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, ep->read_buffer);
 
   SECURE_ENDPOINT_REF(ep, "read");
   if (ep->leftover_bytes.count) {
@@ -264,7 +265,7 @@
   uint8_t *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer);
   uint8_t *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer);
 
-  grpc_slice_buffer_reset_and_unref(&ep->output_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->output_buffer);
 
   if (grpc_trace_secure_endpoint) {
     for (i = 0; i < slices->count; i++) {
@@ -328,11 +329,10 @@
 
   if (result != TSI_OK) {
     /* TODO(yangg) do different things according to the error type? */
-    grpc_slice_buffer_reset_and_unref(&ep->output_buffer);
-    grpc_exec_ctx_sched(
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->output_buffer);
+    grpc_closure_sched(
         exec_ctx, cb,
-        grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
-        NULL);
+        grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result));
     GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
     return;
   }
@@ -372,7 +372,10 @@
   return grpc_endpoint_get_peer(ep->wrapped_ep);
 }
 
-static int endpoint_get_fd(grpc_endpoint *secure_ep) { return -1; }
+static int endpoint_get_fd(grpc_endpoint *secure_ep) {
+  secure_endpoint *ep = (secure_endpoint *)secure_ep;
+  return grpc_endpoint_get_fd(ep->wrapped_ep);
+}
 
 static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) {
   secure_endpoint *ep = (secure_endpoint *)secure_ep;
@@ -407,14 +410,14 @@
   grpc_slice_buffer_init(&ep->leftover_bytes);
   for (i = 0; i < leftover_nslices; i++) {
     grpc_slice_buffer_add(&ep->leftover_bytes,
-                          grpc_slice_ref(leftover_slices[i]));
+                          grpc_slice_ref_internal(leftover_slices[i]));
   }
   ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
   ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE);
   grpc_slice_buffer_init(&ep->output_buffer);
   grpc_slice_buffer_init(&ep->source_buffer);
   ep->read_buffer = NULL;
-  grpc_closure_init(&ep->on_read, on_read, ep);
+  grpc_closure_init(&ep->on_read, on_read, ep, grpc_schedule_on_exec_ctx);
   gpr_mu_init(&ep->protector_mu);
   gpr_ref_init(&ep->ref, 1);
   return &ep->base;
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index 5b088aa..5aa26e0 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -134,9 +134,9 @@
                                         grpc_auth_context **auth_context,
                                         grpc_closure *on_peer_checked) {
   if (sc == NULL) {
-    grpc_exec_ctx_sched(
+    grpc_closure_sched(
         exec_ctx, on_peer_checked,
-        GRPC_ERROR_CREATE("cannot check peer -- no security connector"), NULL);
+        GRPC_ERROR_CREATE("cannot check peer -- no security connector"));
     tsi_peer_destruct(&peer);
   } else {
     sc->vtable->check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked);
@@ -172,7 +172,8 @@
 }
 
 #ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
-void grpc_security_connector_unref(grpc_security_connector *sc,
+void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_security_connector *sc,
                                    const char *file, int line,
                                    const char *reason) {
   if (sc == NULL) return;
@@ -180,14 +181,15 @@
           "SECURITY_CONNECTOR:%p unref %d -> %d %s", sc,
           (int)sc->refcount.count, (int)sc->refcount.count - 1, reason);
 #else
-void grpc_security_connector_unref(grpc_security_connector *sc) {
+void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_security_connector *sc) {
   if (sc == NULL) return;
 #endif
-  if (gpr_unref(&sc->refcount)) sc->vtable->destroy(sc);
+  if (gpr_unref(&sc->refcount)) sc->vtable->destroy(exec_ctx, sc);
 }
 
-static void connector_pointer_arg_destroy(void *p) {
-  GRPC_SECURITY_CONNECTOR_UNREF(p, "connector_pointer_arg_destroy");
+static void connector_pointer_arg_destroy(grpc_exec_ctx *exec_ctx, void *p) {
+  GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, p, "connector_pointer_arg_destroy");
 }
 
 static void *connector_pointer_arg_copy(void *p) {
@@ -233,13 +235,17 @@
 
 /* -- Fake implementation. -- */
 
-static void fake_channel_destroy(grpc_security_connector *sc) {
+static void fake_channel_destroy(grpc_exec_ctx *exec_ctx,
+                                 grpc_security_connector *sc) {
   grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
-  grpc_call_credentials_unref(c->request_metadata_creds);
+  grpc_call_credentials_unref(exec_ctx, c->request_metadata_creds);
   gpr_free(sc);
 }
 
-static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); }
+static void fake_server_destroy(grpc_exec_ctx *exec_ctx,
+                                grpc_security_connector *sc) {
+  gpr_free(sc);
+}
 
 static void fake_check_peer(grpc_exec_ctx *exec_ctx,
                             grpc_security_connector *sc, tsi_peer peer,
@@ -273,7 +279,7 @@
       GRPC_FAKE_TRANSPORT_SECURITY_TYPE);
 
 end:
-  grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
+  grpc_closure_sched(exec_ctx, on_peer_checked, error);
   tsi_peer_destruct(&peer);
 }
 
@@ -351,10 +357,11 @@
   tsi_ssl_handshaker_factory *handshaker_factory;
 } grpc_ssl_server_security_connector;
 
-static void ssl_channel_destroy(grpc_security_connector *sc) {
+static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
+                                grpc_security_connector *sc) {
   grpc_ssl_channel_security_connector *c =
       (grpc_ssl_channel_security_connector *)sc;
-  grpc_call_credentials_unref(c->base.request_metadata_creds);
+  grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds);
   if (c->handshaker_factory != NULL) {
     tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
   }
@@ -363,7 +370,8 @@
   gpr_free(sc);
 }
 
-static void ssl_server_destroy(grpc_security_connector *sc) {
+static void ssl_server_destroy(grpc_exec_ctx *exec_ctx,
+                               grpc_security_connector *sc) {
   grpc_ssl_server_security_connector *c =
       (grpc_ssl_server_security_connector *)sc;
   if (c->handshaker_factory != NULL) {
@@ -508,7 +516,7 @@
                                              ? c->overridden_target_name
                                              : c->target_name,
                                      &peer, auth_context);
-  grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
+  grpc_closure_sched(exec_ctx, on_peer_checked, error);
   tsi_peer_destruct(&peer);
 }
 
@@ -518,7 +526,7 @@
                                   grpc_closure *on_peer_checked) {
   grpc_error *error = ssl_check_peer(sc, NULL, &peer, auth_context);
   tsi_peer_destruct(&peer);
-  grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL);
+  grpc_closure_sched(exec_ctx, on_peer_checked, error);
 }
 
 static void add_shallow_auth_property_to_peer(tsi_peer *peer,
@@ -669,7 +677,7 @@
 }
 
 grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_call_credentials *request_metadata_creds,
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds,
     const grpc_ssl_config *config, const char *target_name,
     const char *overridden_target_name, grpc_channel_security_connector **sc) {
   size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
@@ -730,7 +738,7 @@
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
-    ssl_channel_destroy(&c->base.base);
+    ssl_channel_destroy(exec_ctx, &c->base.base);
     *sc = NULL;
     goto error;
   }
@@ -746,7 +754,8 @@
 }
 
 grpc_security_status grpc_ssl_server_security_connector_create(
-    const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
+    grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
+    grpc_server_security_connector **sc) {
   size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
   const unsigned char **alpn_protocol_strings =
       gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@@ -786,7 +795,7 @@
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
             tsi_result_to_string(result));
-    ssl_server_destroy(&c->base.base);
+    ssl_server_destroy(exec_ctx, &c->base.base);
     *sc = NULL;
     goto error;
   }
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index a84b359..eba4e6d 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -60,7 +60,7 @@
 #define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector"
 
 typedef struct {
-  void (*destroy)(grpc_security_connector *sc);
+  void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc);
   void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
                      tsi_peer peer, grpc_auth_context **auth_context,
                      grpc_closure *on_peer_checked);
@@ -81,20 +81,23 @@
 #ifdef GRPC_SECURITY_CONNECTOR_REFCOUNT_DEBUG
 #define GRPC_SECURITY_CONNECTOR_REF(p, r) \
   grpc_security_connector_ref((p), __FILE__, __LINE__, (r))
-#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) \
-  grpc_security_connector_unref((p), __FILE__, __LINE__, (r))
+#define GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, p, r) \
+  grpc_security_connector_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
 grpc_security_connector *grpc_security_connector_ref(
     grpc_security_connector *policy, const char *file, int line,
     const char *reason);
-void grpc_security_connector_unref(grpc_security_connector *policy,
+void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_security_connector *policy,
                                    const char *file, int line,
                                    const char *reason);
 #else
 #define GRPC_SECURITY_CONNECTOR_REF(p, r) grpc_security_connector_ref((p))
-#define GRPC_SECURITY_CONNECTOR_UNREF(p, r) grpc_security_connector_unref((p))
+#define GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, p, r) \
+  grpc_security_connector_unref((exec_ctx), (p))
 grpc_security_connector *grpc_security_connector_ref(
     grpc_security_connector *policy);
-void grpc_security_connector_unref(grpc_security_connector *policy);
+void grpc_security_connector_unref(grpc_exec_ctx *exec_ctx,
+                                   grpc_security_connector *policy);
 #endif
 
 /* Check the peer. Callee takes ownership of the peer object.
@@ -203,7 +206,7 @@
   specific error code otherwise.
 */
 grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_call_credentials *request_metadata_creds,
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *request_metadata_creds,
     const grpc_ssl_config *config, const char *target_name,
     const char *overridden_target_name, grpc_channel_security_connector **sc);
 
@@ -232,7 +235,8 @@
   specific error code otherwise.
 */
 grpc_security_status grpc_ssl_server_security_connector_create(
-    const grpc_ssl_server_config *config, grpc_server_security_connector **sc);
+    grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
+    grpc_server_security_connector **sc);
 
 /* Util. */
 const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c
index 41a775d..5e75856 100644
--- a/src/core/lib/security/transport/security_handshaker.c
+++ b/src/core/lib/security/transport/security_handshaker.c
@@ -42,9 +42,11 @@
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
 #include "src/core/lib/security/transport/tsi_error.h"
+#include "src/core/lib/slice/slice_internal.h"
 
 #define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256
 
@@ -86,26 +88,27 @@
       grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy);
     }
     if (h->read_buffer_to_destroy != NULL) {
-      grpc_slice_buffer_destroy(h->read_buffer_to_destroy);
+      grpc_slice_buffer_destroy_internal(exec_ctx, h->read_buffer_to_destroy);
       gpr_free(h->read_buffer_to_destroy);
     }
     gpr_free(h->handshake_buffer);
-    grpc_slice_buffer_destroy(&h->left_overs);
-    grpc_slice_buffer_destroy(&h->outgoing);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &h->left_overs);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &h->outgoing);
     GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake");
-    GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake");
+    GRPC_SECURITY_CONNECTOR_UNREF(exec_ctx, h->connector, "handshake");
     gpr_free(h);
   }
 }
 
 // Set args fields to NULL, saving the endpoint and read buffer for
 // later destruction.
-static void cleanup_args_for_failure_locked(security_handshaker *h) {
+static void cleanup_args_for_failure_locked(grpc_exec_ctx *exec_ctx,
+                                            security_handshaker *h) {
   h->endpoint_to_destroy = h->args->endpoint;
   h->args->endpoint = NULL;
   h->read_buffer_to_destroy = h->args->read_buffer;
   h->args->read_buffer = NULL;
-  grpc_channel_args_destroy(h->args->args);
+  grpc_channel_args_destroy(exec_ctx, h->args->args);
   h->args->args = NULL;
 }
 
@@ -130,13 +133,13 @@
     grpc_endpoint_shutdown(exec_ctx, h->args->endpoint);
     // Not shutting down, so the write failed.  Clean up before
     // invoking the callback.
-    cleanup_args_for_failure_locked(h);
+    cleanup_args_for_failure_locked(exec_ctx, h);
     // Set shutdown to true so that subsequent calls to
     // security_handshaker_shutdown() do nothing.
     h->shutdown = true;
   }
   // Invoke callback.
-  grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, NULL);
+  grpc_closure_sched(exec_ctx, h->on_handshake_done, error);
 }
 
 static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg,
@@ -165,15 +168,15 @@
   h->left_overs.length = 0;
   // Clear out the read buffer before it gets passed to the transport,
   // since any excess bytes were already copied to h->left_overs.
-  grpc_slice_buffer_reset_and_unref(h->args->read_buffer);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, h->args->read_buffer);
   // Add auth context to channel args.
   grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context);
   grpc_channel_args *tmp_args = h->args->args;
   h->args->args =
       grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1);
-  grpc_channel_args_destroy(tmp_args);
+  grpc_channel_args_destroy(exec_ctx, tmp_args);
   // Invoke callback.
-  grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE);
   // Set shutdown to true so that subsequent calls to
   // security_handshaker_shutdown() do nothing.
   h->shutdown = true;
@@ -218,7 +221,7 @@
   // Send data.
   grpc_slice to_send =
       grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset);
-  grpc_slice_buffer_reset_and_unref(&h->outgoing);
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &h->outgoing);
   grpc_slice_buffer_add(&h->outgoing, to_send);
   grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing,
                       &h->on_handshake_data_sent_to_peer);
@@ -287,7 +290,7 @@
           grpc_slice_split_tail(&h->args->read_buffer->slices[i],
                                 consumed_slice_size));
       /* split_tail above increments refcount. */
-      grpc_slice_unref(h->args->read_buffer->slices[i]);
+      grpc_slice_unref_internal(exec_ctx, h->args->read_buffer->slices[i]);
     }
     grpc_slice_buffer_addn(
         &h->left_overs, &h->args->read_buffer->slices[i + 1],
@@ -350,7 +353,7 @@
   if (!h->shutdown) {
     h->shutdown = true;
     grpc_endpoint_shutdown(exec_ctx, h->args->endpoint);
-    cleanup_args_for_failure_locked(h);
+    cleanup_args_for_failure_locked(exec_ctx, h);
   }
   gpr_mu_unlock(&h->mu);
 }
@@ -392,10 +395,13 @@
   h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
   h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
   grpc_closure_init(&h->on_handshake_data_sent_to_peer,
-                    on_handshake_data_sent_to_peer, h);
+                    on_handshake_data_sent_to_peer, h,
+                    grpc_schedule_on_exec_ctx);
   grpc_closure_init(&h->on_handshake_data_received_from_peer,
-                    on_handshake_data_received_from_peer, h);
-  grpc_closure_init(&h->on_peer_checked, on_peer_checked, h);
+                    on_handshake_data_received_from_peer, h,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&h->on_peer_checked, on_peer_checked, h,
+                    grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&h->left_overs);
   grpc_slice_buffer_init(&h->outgoing);
   return &h->base;
@@ -418,9 +424,8 @@
                                          grpc_tcp_server_acceptor *acceptor,
                                          grpc_closure *on_handshake_done,
                                          grpc_handshaker_args *args) {
-  grpc_exec_ctx_sched(exec_ctx, on_handshake_done,
-                      GRPC_ERROR_CREATE("Failed to create security handshaker"),
-                      NULL);
+  grpc_closure_sched(exec_ctx, on_handshake_done,
+                     GRPC_ERROR_CREATE("Failed to create security handshaker"));
 }
 
 static const grpc_handshaker_vtable fail_handshaker_vtable = {
@@ -434,6 +439,45 @@
 }
 
 //
+// handshaker factories
+//
+
+static void client_handshaker_factory_add_handshakers(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory,
+    const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) {
+  grpc_channel_security_connector *security_connector =
+      (grpc_channel_security_connector *)grpc_find_security_connector_in_args(
+          args);
+  grpc_channel_security_connector_add_handshakers(exec_ctx, security_connector,
+                                                  handshake_mgr);
+}
+
+static void server_handshaker_factory_add_handshakers(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *hf,
+    const grpc_channel_args *args, grpc_handshake_manager *handshake_mgr) {
+  grpc_server_security_connector *security_connector =
+      (grpc_server_security_connector *)grpc_find_security_connector_in_args(
+          args);
+  grpc_server_security_connector_add_handshakers(exec_ctx, security_connector,
+                                                 handshake_mgr);
+}
+
+static void handshaker_factory_destroy(
+    grpc_exec_ctx *exec_ctx, grpc_handshaker_factory *handshaker_factory) {}
+
+static const grpc_handshaker_factory_vtable client_handshaker_factory_vtable = {
+    client_handshaker_factory_add_handshakers, handshaker_factory_destroy};
+
+static grpc_handshaker_factory client_handshaker_factory = {
+    &client_handshaker_factory_vtable};
+
+static const grpc_handshaker_factory_vtable server_handshaker_factory_vtable = {
+    server_handshaker_factory_add_handshakers, handshaker_factory_destroy};
+
+static grpc_handshaker_factory server_handshaker_factory = {
+    &server_handshaker_factory_vtable};
+
+//
 // exported functions
 //
 
@@ -448,3 +492,10 @@
     return security_handshaker_create(exec_ctx, handshaker, connector);
   }
 }
+
+void grpc_security_register_handshaker_factories() {
+  grpc_handshaker_factory_register(false /* at_start */, HANDSHAKER_CLIENT,
+                                   &client_handshaker_factory);
+  grpc_handshaker_factory_register(false /* at_start */, HANDSHAKER_SERVER,
+                                   &server_handshaker_factory);
+}
diff --git a/src/core/lib/security/transport/security_handshaker.h b/src/core/lib/security/transport/security_handshaker.h
index 5ddbf4b..0b9eda1 100644
--- a/src/core/lib/security/transport/security_handshaker.h
+++ b/src/core/lib/security/transport/security_handshaker.h
@@ -43,4 +43,7 @@
     grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
     grpc_security_connector *connector);
 
+/// Registers security handshaker factories.
+void grpc_security_register_handshaker_factories();
+
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index eaa1d07..5e98ba8 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -83,7 +83,8 @@
   return result;
 }
 
-static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *remove_consumed_md(grpc_exec_ctx *exec_ctx, void *user_data,
+                                       grpc_mdelem *md) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   size_t i;
@@ -129,10 +130,10 @@
   if (status == GRPC_STATUS_OK) {
     calld->consumed_md = consumed_md;
     calld->num_consumed_md = num_consumed_md;
-    grpc_metadata_batch_filter(calld->recv_initial_metadata, remove_consumed_md,
-                               elem);
+    grpc_metadata_batch_filter(&exec_ctx, calld->recv_initial_metadata,
+                               remove_consumed_md, elem);
     grpc_metadata_array_destroy(&calld->md);
-    grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE);
   } else {
     grpc_slice message;
     grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op));
@@ -148,13 +149,13 @@
       calld->transport_op->send_message = NULL;
     }
     calld->transport_op->send_trailing_metadata = NULL;
-    close_op->on_complete = grpc_closure_create(destroy_op, close_op);
-    grpc_transport_stream_op_add_close(close_op, status, &message);
+    close_op->on_complete =
+        grpc_closure_create(destroy_op, close_op, grpc_schedule_on_exec_ctx);
+    grpc_transport_stream_op_add_close(&exec_ctx, close_op, status, &message);
     grpc_call_next_op(&exec_ctx, elem, close_op);
-    grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv,
-                        grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
-                                           GRPC_ERROR_INT_GRPC_STATUS, status),
-                        NULL);
+    grpc_closure_sched(&exec_ctx, calld->on_done_recv,
+                       grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
+                                          GRPC_ERROR_INT_GRPC_STATUS, status));
   }
 
   grpc_exec_ctx_finish(&exec_ctx);
@@ -174,8 +175,7 @@
       return;
     }
   }
-  grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv, GRPC_ERROR_REF(error),
-                      NULL);
+  grpc_closure_sched(exec_ctx, calld->on_done_recv, GRPC_ERROR_REF(error));
 }
 
 static void set_recv_ops_md_callbacks(grpc_call_element *elem,
@@ -214,7 +214,8 @@
 
   /* initialize members */
   memset(calld, 0, sizeof(*calld));
-  grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem);
+  grpc_closure_init(&calld->auth_on_recv, auth_on_recv, elem,
+                    grpc_schedule_on_exec_ctx);
 
   if (args->context[GRPC_CONTEXT_SECURITY].value != NULL) {
     args->context[GRPC_CONTEXT_SECURITY].destroy(
@@ -238,9 +239,9 @@
                               void *ignored) {}
 
 /* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   grpc_auth_context *auth_context =
       grpc_find_auth_context_in_args(args->channel_args);
   grpc_server_credentials *creds =
@@ -256,6 +257,7 @@
   chand->auth_context =
       GRPC_AUTH_CONTEXT_REF(auth_context, "server_auth_filter");
   chand->creds = grpc_server_credentials_ref(creds);
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for channel data */
@@ -264,7 +266,7 @@
   /* grab pointers to our data from the channel element */
   channel_data *chand = elem->channel_data;
   GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "server_auth_filter");
-  grpc_server_credentials_unref(chand->creds);
+  grpc_server_credentials_unref(exec_ctx, chand->creds);
 }
 
 const grpc_channel_filter grpc_server_auth_filter = {
diff --git a/src/core/lib/security/util/b64.c b/src/core/lib/security/util/b64.c
index 4892e8e..bbd7e33 100644
--- a/src/core/lib/security/util/b64.c
+++ b/src/core/lib/security/util/b64.c
@@ -40,6 +40,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 /* --- Constants. --- */
 
 static const int8_t base64_bytes[] = {
@@ -120,8 +122,9 @@
   return result;
 }
 
-grpc_slice grpc_base64_decode(const char *b64, int url_safe) {
-  return grpc_base64_decode_with_len(b64, strlen(b64), url_safe);
+grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
+                              int url_safe) {
+  return grpc_base64_decode_with_len(exec_ctx, b64, strlen(b64), url_safe);
 }
 
 static void decode_one_char(const unsigned char *codes, unsigned char *result,
@@ -182,8 +185,8 @@
   return 1;
 }
 
-grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
-                                       int url_safe) {
+grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64,
+                                       size_t b64_len, int url_safe) {
   grpc_slice result = grpc_slice_malloc(b64_len);
   unsigned char *current = GRPC_SLICE_START_PTR(result);
   size_t result_size = 0;
@@ -228,6 +231,6 @@
   return result;
 
 fail:
-  grpc_slice_unref(result);
+  grpc_slice_unref_internal(exec_ctx, result);
   return gpr_empty_slice();
 }
diff --git a/src/core/lib/security/util/b64.h b/src/core/lib/security/util/b64.h
index 6ea0b53..d42a136 100644
--- a/src/core/lib/security/util/b64.h
+++ b/src/core/lib/security/util/b64.h
@@ -43,10 +43,11 @@
 
 /* Decodes data according to the base64 specification. Returns an empty
    slice in case of failure. */
-grpc_slice grpc_base64_decode(const char *b64, int url_safe);
+grpc_slice grpc_base64_decode(grpc_exec_ctx *exec_ctx, const char *b64,
+                              int url_safe);
 
 /* Same as above except that the length is provided by the caller. */
-grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len,
-                                       int url_safe);
+grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx *exec_ctx, const char *b64,
+                                       size_t b64_len, int url_safe);
 
 #endif /* GRPC_CORE_LIB_SECURITY_UTIL_B64_H */
diff --git a/src/core/lib/slice/percent_encoding.c b/src/core/lib/slice/percent_encoding.c
index b9e35f1..c76c58d 100644
--- a/src/core/lib/slice/percent_encoding.c
+++ b/src/core/lib/slice/percent_encoding.c
@@ -35,6 +35,8 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 const uint8_t grpc_url_percent_encoding_unreserved_bytes[256 / 8] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0xfe, 0xff, 0xff,
     0x87, 0xfe, 0xff, 0xff, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -66,7 +68,7 @@
   }
   // no unreserved bytes: return the string unmodified
   if (!any_reserved_bytes) {
-    return grpc_slice_ref(slice);
+    return grpc_slice_ref_internal(slice);
   }
   // second pass: actually encode
   grpc_slice out = grpc_slice_malloc(output_length);
@@ -119,7 +121,7 @@
     }
   }
   if (!any_percent_encoded_stuff) {
-    *slice_out = grpc_slice_ref(slice_in);
+    *slice_out = grpc_slice_ref_internal(slice_in);
     return true;
   }
   p = GRPC_SLICE_START_PTR(slice_in);
@@ -158,7 +160,7 @@
     }
   }
   if (!any_percent_encoded_stuff) {
-    return grpc_slice_ref(slice_in);
+    return grpc_slice_ref_internal(slice_in);
   }
   p = GRPC_SLICE_START_PTR(slice_in);
   grpc_slice out = grpc_slice_malloc(out_length);
diff --git a/src/core/lib/slice/slice.c b/src/core/lib/slice/slice.c
index 52977e6..7611810 100644
--- a/src/core/lib/slice/slice.c
+++ b/src/core/lib/slice/slice.c
@@ -31,12 +31,16 @@
  *
  */
 
+#include "src/core/lib/slice/slice_internal.h"
+
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include <string.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
+
 grpc_slice gpr_empty_slice(void) {
   grpc_slice out;
   out.refcount = 0;
@@ -44,25 +48,37 @@
   return out;
 }
 
-grpc_slice grpc_slice_ref(grpc_slice slice) {
+grpc_slice grpc_slice_ref_internal(grpc_slice slice) {
   if (slice.refcount) {
     slice.refcount->ref(slice.refcount);
   }
   return slice;
 }
 
-void grpc_slice_unref(grpc_slice slice) {
+void grpc_slice_unref_internal(grpc_exec_ctx *exec_ctx, grpc_slice slice) {
   if (slice.refcount) {
-    slice.refcount->unref(slice.refcount);
+    slice.refcount->unref(exec_ctx, slice.refcount);
   }
 }
 
+/* Public API */
+grpc_slice grpc_slice_ref(grpc_slice slice) {
+  return grpc_slice_ref_internal(slice);
+}
+
+/* Public API */
+void grpc_slice_unref(grpc_slice slice) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_slice_unref_internal(&exec_ctx, slice);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
 /* grpc_slice_from_static_string support structure - a refcount that does
    nothing */
-static void noop_ref_or_unref(void *unused) {}
+static void noop_ref(void *unused) {}
+static void noop_unref(grpc_exec_ctx *exec_ctx, void *unused) {}
 
-static grpc_slice_refcount noop_refcount = {noop_ref_or_unref,
-                                            noop_ref_or_unref};
+static grpc_slice_refcount noop_refcount = {noop_ref, noop_unref};
 
 grpc_slice grpc_slice_from_static_string(const char *s) {
   grpc_slice slice;
@@ -86,7 +102,7 @@
   gpr_ref(&r->refs);
 }
 
-static void new_slice_unref(void *p) {
+static void new_slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
   new_slice_refcount *r = p;
   if (gpr_unref(&r->refs)) {
     r->user_destroy(r->user_data);
@@ -131,7 +147,7 @@
   gpr_ref(&r->refs);
 }
 
-static void new_with_len_unref(void *p) {
+static void new_with_len_unref(grpc_exec_ctx *exec_ctx, void *p) {
   new_with_len_slice_refcount *r = p;
   if (gpr_unref(&r->refs)) {
     r->user_destroy(r->user_data, r->user_length);
@@ -177,7 +193,7 @@
   gpr_ref(&r->refs);
 }
 
-static void malloc_unref(void *p) {
+static void malloc_unref(grpc_exec_ctx *exec_ctx, void *p) {
   malloc_refcount *r = p;
   if (gpr_unref(&r->refs)) {
     gpr_free(r);
diff --git a/src/core/lib/slice/slice_buffer.c b/src/core/lib/slice/slice_buffer.c
index 990ef12..08eaf49 100644
--- a/src/core/lib/slice/slice_buffer.c
+++ b/src/core/lib/slice/slice_buffer.c
@@ -40,6 +40,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
 #define GROW(x) (3 * (x) / 2)
 
@@ -63,13 +65,20 @@
   sb->slices = sb->inlined;
 }
 
-void grpc_slice_buffer_destroy(grpc_slice_buffer *sb) {
-  grpc_slice_buffer_reset_and_unref(sb);
+void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx,
+                                        grpc_slice_buffer *sb) {
+  grpc_slice_buffer_reset_and_unref_internal(exec_ctx, sb);
   if (sb->slices != sb->inlined) {
     gpr_free(sb->slices);
   }
 }
 
+void grpc_slice_buffer_destroy(grpc_slice_buffer *sb) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_slice_buffer_destroy_internal(&exec_ctx, sb);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
 uint8_t *grpc_slice_buffer_tiny_add(grpc_slice_buffer *sb, size_t n) {
   grpc_slice *back;
   uint8_t *out;
@@ -154,17 +163,24 @@
   }
 }
 
-void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer *sb) {
+void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx,
+                                                grpc_slice_buffer *sb) {
   size_t i;
 
   for (i = 0; i < sb->count; i++) {
-    grpc_slice_unref(sb->slices[i]);
+    grpc_slice_unref_internal(exec_ctx, sb->slices[i]);
   }
 
   sb->count = 0;
   sb->length = 0;
 }
 
+void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer *sb) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, sb);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
 void grpc_slice_buffer_swap(grpc_slice_buffer *a, grpc_slice_buffer *b) {
   GPR_SWAP(size_t, a->count, b->count);
   GPR_SWAP(size_t, a->capacity, b->capacity);
diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h
new file mode 100644
index 0000000..6185333
--- /dev/null
+++ b/src/core/lib/slice/slice_internal.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H
+#define GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H
+
+#include <grpc/slice.h>
+#include <grpc/slice_buffer.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+grpc_slice grpc_slice_ref_internal(grpc_slice slice);
+void grpc_slice_unref_internal(grpc_exec_ctx *exec_ctx, grpc_slice slice);
+void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx,
+                                                grpc_slice_buffer *sb);
+void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx,
+                                        grpc_slice_buffer *sb);
+
+#endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */
diff --git a/src/core/lib/slice/slice_string_helpers.c b/src/core/lib/slice/slice_string_helpers.c
index 4731762..839c366 100644
--- a/src/core/lib/slice/slice_string_helpers.c
+++ b/src/core/lib/slice/slice_string_helpers.c
@@ -37,6 +37,7 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 
 char *grpc_dump_slice(grpc_slice s, uint32_t flags) {
@@ -84,6 +85,6 @@
     grpc_slice_buffer_add_indexed(
         dst, grpc_slice_sub(str, end + sep_len, GRPC_SLICE_LENGTH(str)));
   } else { /* no sep found, add whole input */
-    grpc_slice_buffer_add_indexed(dst, grpc_slice_ref(str));
+    grpc_slice_buffer_add_indexed(dst, grpc_slice_ref_internal(str));
   }
 }
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
index f10a30f..d20b86f 100644
--- a/src/core/lib/support/string.c
+++ b/src/core/lib/support/string.c
@@ -275,3 +275,41 @@
   } while (ca == cb && ca && cb);
   return ca - cb;
 }
+
+static void add_string_to_split(const char *beg, const char *end, char ***strs,
+                                size_t *nstrs, size_t *capstrs) {
+  char *out = gpr_malloc((size_t)(end - beg) + 1);
+  memcpy(out, beg, (size_t)(end - beg));
+  out[end - beg] = 0;
+  if (*nstrs == *capstrs) {
+    *capstrs = GPR_MAX(8, 2 * *capstrs);
+    *strs = gpr_realloc(*strs, sizeof(*strs) * *capstrs);
+  }
+  (*strs)[*nstrs] = out;
+  ++*nstrs;
+}
+
+void gpr_string_split(const char *input, const char *sep, char ***strs,
+                      size_t *nstrs) {
+  char *next;
+  *strs = NULL;
+  *nstrs = 0;
+  size_t capstrs = 0;
+  while ((next = strstr(input, sep))) {
+    add_string_to_split(input, next, strs, nstrs, &capstrs);
+    input = next + strlen(sep);
+  }
+  add_string_to_split(input, input + strlen(input), strs, nstrs, &capstrs);
+}
+
+void *gpr_memrchr(const void *s, int c, size_t n) {
+  if (s == NULL) return NULL;
+  char *b = (char *)s;
+  size_t i;
+  for (i = 0; i < n; i++) {
+    if (b[n - i - 1] == c) {
+      return &b[n - i - 1];
+    }
+  }
+  return NULL;
+}
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index e933e2e..d1c52fa 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -36,8 +36,6 @@
 
 #include <stddef.h>
 
-#include <grpc/slice.h>
-#include <grpc/slice_buffer.h>
 #include <grpc/support/port_platform.h>
 
 #ifdef __cplusplus
@@ -98,6 +96,9 @@
 char *gpr_strjoin_sep(const char **strs, size_t nstrs, const char *sep,
                       size_t *total_length);
 
+void gpr_string_split(const char *input, const char *sep, char ***strs,
+                      size_t *nstrs);
+
 /* A vector of strings... for building up a final string one piece at a time */
 typedef struct {
   char **strs;
@@ -118,6 +119,8 @@
     lower(a)==lower(b), >0 if lower(a)>lower(b) */
 int gpr_stricmp(const char *a, const char *b);
 
+void *gpr_memrchr(const void *s, int c, size_t n);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/lib/support/tmpfile.h b/src/core/lib/support/tmpfile.h
index 8952e5e..f613cf9 100644
--- a/src/core/lib/support/tmpfile.h
+++ b/src/core/lib/support/tmpfile.h
@@ -36,8 +36,6 @@
 
 #include <stdio.h>
 
-#include <grpc/slice.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/core/lib/surface/README.md b/src/core/lib/surface/README.md
new file mode 100644
index 0000000..74cbd71
--- /dev/null
+++ b/src/core/lib/surface/README.md
@@ -0,0 +1,4 @@
+# Surface
+
+Surface provides the bulk of the gRPC Core public API, and translates it into
+calls against core components.
diff --git a/src/core/lib/surface/alarm.c b/src/core/lib/surface/alarm.c
index aa9d60e..e71c0eb 100644
--- a/src/core/lib/surface/alarm.c
+++ b/src/core/lib/surface/alarm.c
@@ -38,6 +38,7 @@
 
 struct grpc_alarm {
   grpc_timer alarm;
+  grpc_closure on_alarm;
   grpc_cq_completion completion;
   /** completion queue where events about this alarm will be posted */
   grpc_completion_queue *cq;
@@ -64,9 +65,11 @@
   alarm->tag = tag;
 
   grpc_cq_begin_op(cq, tag);
+  grpc_closure_init(&alarm->on_alarm, alarm_cb, alarm,
+                    grpc_schedule_on_exec_ctx);
   grpc_timer_init(&exec_ctx, &alarm->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
   grpc_exec_ctx_finish(&exec_ctx);
   return alarm;
 }
diff --git a/src/core/lib/surface/byte_buffer.c b/src/core/lib/surface/byte_buffer.c
index d646591..c8e2fdf 100644
--- a/src/core/lib/surface/byte_buffer.c
+++ b/src/core/lib/surface/byte_buffer.c
@@ -35,6 +35,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 grpc_byte_buffer *grpc_raw_byte_buffer_create(grpc_slice *slices,
                                               size_t nslices) {
   return grpc_raw_compressed_byte_buffer_create(slices, nslices,
@@ -50,7 +52,7 @@
   bb->data.raw.compression = compression;
   grpc_slice_buffer_init(&bb->data.raw.slice_buffer);
   for (i = 0; i < nslices; i++) {
-    grpc_slice_ref(slices[i]);
+    grpc_slice_ref_internal(slices[i]);
     grpc_slice_buffer_add(&bb->data.raw.slice_buffer, slices[i]);
   }
   return bb;
@@ -82,12 +84,14 @@
 
 void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
   if (!bb) return;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   switch (bb->type) {
     case GRPC_BB_RAW:
-      grpc_slice_buffer_destroy(&bb->data.raw.slice_buffer);
+      grpc_slice_buffer_destroy_internal(&exec_ctx, &bb->data.raw.slice_buffer);
       break;
   }
   gpr_free(bb);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
diff --git a/src/core/lib/surface/byte_buffer_reader.c b/src/core/lib/surface/byte_buffer_reader.c
index 0089959..1a6ccda 100644
--- a/src/core/lib/surface/byte_buffer_reader.c
+++ b/src/core/lib/surface/byte_buffer_reader.c
@@ -42,6 +42,7 @@
 #include <grpc/support/log.h>
 
 #include "src/core/lib/compression/message_compress.h"
+#include "src/core/lib/slice/slice_internal.h"
 
 static int is_compressed(grpc_byte_buffer *buffer) {
   switch (buffer->type) {
@@ -56,13 +57,15 @@
 
 int grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
                                  grpc_byte_buffer *buffer) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_slice_buffer decompressed_slices_buffer;
   reader->buffer_in = buffer;
   switch (reader->buffer_in->type) {
     case GRPC_BB_RAW:
       grpc_slice_buffer_init(&decompressed_slices_buffer);
       if (is_compressed(reader->buffer_in)) {
-        if (grpc_msg_decompress(reader->buffer_in->data.raw.compression,
+        if (grpc_msg_decompress(&exec_ctx,
+                                reader->buffer_in->data.raw.compression,
                                 &reader->buffer_in->data.raw.slice_buffer,
                                 &decompressed_slices_buffer) == 0) {
           gpr_log(GPR_ERROR,
@@ -76,13 +79,15 @@
               grpc_raw_byte_buffer_create(decompressed_slices_buffer.slices,
                                           decompressed_slices_buffer.count);
         }
-        grpc_slice_buffer_destroy(&decompressed_slices_buffer);
+        grpc_slice_buffer_destroy_internal(&exec_ctx,
+                                           &decompressed_slices_buffer);
       } else { /* not compressed, use the input buffer as output */
         reader->buffer_out = reader->buffer_in;
       }
       reader->current.index = 0;
       break;
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   return 1;
 }
 
@@ -104,7 +109,8 @@
       grpc_slice_buffer *slice_buffer;
       slice_buffer = &reader->buffer_out->data.raw.slice_buffer;
       if (reader->current.index < slice_buffer->count) {
-        *slice = grpc_slice_ref(slice_buffer->slices[reader->current.index]);
+        *slice = grpc_slice_ref_internal(
+            slice_buffer->slices[reader->current.index]);
         reader->current.index += 1;
         return 1;
       }
@@ -121,12 +127,14 @@
   grpc_slice out_slice = grpc_slice_malloc(input_size);
   uint8_t *const outbuf = GRPC_SLICE_START_PTR(out_slice); /* just an alias */
 
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   while (grpc_byte_buffer_reader_next(reader, &in_slice) != 0) {
     const size_t slice_length = GRPC_SLICE_LENGTH(in_slice);
     memcpy(&(outbuf[bytes_read]), GRPC_SLICE_START_PTR(in_slice), slice_length);
     bytes_read += slice_length;
-    grpc_slice_unref(in_slice);
+    grpc_slice_unref_internal(&exec_ctx, in_slice);
     GPR_ASSERT(bytes_read <= input_size);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   return out_slice;
 }
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 8ca3cab..899e8fa 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -49,6 +49,7 @@
 #include "src/core/lib/compression/algorithm_metadata.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -226,12 +227,12 @@
 static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
                                   grpc_error *error);
 
-grpc_error *grpc_call_create(const grpc_call_create_args *args,
+grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
+                             const grpc_call_create_args *args,
                              grpc_call **out_call) {
   size_t i, j;
   grpc_channel_stack *channel_stack =
       grpc_channel_get_channel_stack(args->channel);
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_call *call;
   GPR_TIMER_BEGIN("grpc_call_create", 0);
   call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
@@ -315,14 +316,14 @@
   GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
   /* initial refcount dropped by grpc_call_destroy */
   grpc_error *error = grpc_call_stack_init(
-      &exec_ctx, channel_stack, 1, destroy_call, call, call->context,
+      exec_ctx, channel_stack, 1, destroy_call, call, call->context,
       args->server_transport_data, path, call->start_time, send_deadline,
       CALL_STACK_FROM_CALL(call));
   if (error != GRPC_ERROR_NONE) {
     grpc_status_code status;
     const char *error_str;
     grpc_error_get_status(error, &status, &error_str);
-    close_with_status(&exec_ctx, call, status, error_str);
+    close_with_status(exec_ctx, call, status, error_str);
   }
   if (args->cq != NULL) {
     GPR_ASSERT(
@@ -338,12 +339,11 @@
   }
   if (!grpc_polling_entity_is_empty(&call->pollent)) {
     grpc_call_stack_set_pollset_or_pollset_set(
-        &exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
+        exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
   }
 
-  if (path != NULL) GRPC_MDSTR_UNREF(path);
+  if (path != NULL) GRPC_MDSTR_UNREF(exec_ctx, path);
 
-  grpc_exec_ctx_finish(&exec_ctx);
   GPR_TIMER_END("grpc_call_create", 0);
   return error;
 }
@@ -404,7 +404,7 @@
   GPR_TIMER_BEGIN("destroy_call", 0);
   for (i = 0; i < 2; i++) {
     grpc_metadata_batch_destroy(
-        &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]);
+        exec_ctx, &c->metadata_batch[1 /* is_receiving */][i /* is_initial */]);
   }
   if (c->receiving_stream != NULL) {
     grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
@@ -412,11 +412,11 @@
   gpr_mu_destroy(&c->mu);
   for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
     if (c->status[i].details) {
-      GRPC_MDSTR_UNREF(c->status[i].details);
+      GRPC_MDSTR_UNREF(exec_ctx, c->status[i].details);
     }
   }
   for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
-    GRPC_MDELEM_UNREF(c->send_extra_metadata[ii].md);
+    GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
   }
   for (i = 0; i < GRPC_CONTEXT_COUNT; i++) {
     if (c->context[i].destroy) {
@@ -446,22 +446,22 @@
   call->status[source].code = (grpc_status_code)status;
 }
 
-static void set_status_details(grpc_call *call, status_source source,
-                               grpc_mdstr *status) {
+static void set_status_details(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                               status_source source, grpc_mdstr *status) {
   if (call->status[source].details != NULL) {
-    GRPC_MDSTR_UNREF(status);
+    GRPC_MDSTR_UNREF(exec_ctx, status);
   } else {
     call->status[source].details = status;
   }
 }
 
-static void set_status_from_error(grpc_call *call, status_source source,
-                                  grpc_error *error) {
+static void set_status_from_error(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                                  status_source source, grpc_error *error) {
   grpc_status_code status;
   const char *msg;
   grpc_error_get_status(error, &status, &msg);
   set_status_code(call, source, (uint32_t)status);
-  set_status_details(call, source, grpc_mdstr_from_string(msg));
+  set_status_details(exec_ctx, call, source, grpc_mdstr_from_string(msg));
 }
 
 static void set_incoming_compression_algorithm(
@@ -495,7 +495,8 @@
 
 static void destroy_encodings_accepted_by_peer(void *p) { return; }
 
-static void set_encodings_accepted_by_peer(grpc_call *call, grpc_mdelem *mdel) {
+static void set_encodings_accepted_by_peer(grpc_exec_ctx *exec_ctx,
+                                           grpc_call *call, grpc_mdelem *mdel) {
   size_t i;
   grpc_compression_algorithm algorithm;
   grpc_slice_buffer accept_encoding_parts;
@@ -535,7 +536,7 @@
     }
   }
 
-  grpc_slice_buffer_destroy(&accept_encoding_parts);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &accept_encoding_parts);
 
   grpc_mdelem_set_user_data(
       mdel, destroy_encodings_accepted_by_peer,
@@ -593,12 +594,10 @@
   return res;
 }
 
-static int prepare_application_metadata(grpc_call *call, int count,
-                                        grpc_metadata *metadata,
-                                        int is_trailing,
-                                        int prepend_extra_metadata,
-                                        grpc_metadata *additional_metadata,
-                                        int additional_metadata_count) {
+static int prepare_application_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call *call, int count,
+    grpc_metadata *metadata, int is_trailing, int prepend_extra_metadata,
+    grpc_metadata *additional_metadata, int additional_metadata_count) {
   int total_count = count + additional_metadata_count;
   int i;
   grpc_metadata_batch *batch =
@@ -609,7 +608,7 @@
     grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
     GPR_ASSERT(sizeof(grpc_linked_mdelem) == sizeof(md->internal_data));
     l->md = grpc_mdelem_from_string_and_buffer(
-        md->key, (const uint8_t *)md->value, md->value_length);
+        exec_ctx, md->key, (const uint8_t *)md->value, md->value_length);
     if (!grpc_header_key_is_legal(grpc_mdstr_as_c_string(l->md->key),
                                   GRPC_MDSTR_LENGTH(l->md->key))) {
       gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s",
@@ -629,7 +628,7 @@
       const grpc_metadata *md =
           get_md_elem(metadata, additional_metadata, j, count);
       grpc_linked_mdelem *l = (grpc_linked_mdelem *)&md->internal_data;
-      GRPC_MDELEM_UNREF(l->md);
+      GRPC_MDELEM_UNREF(exec_ctx, l->md);
     }
     return 0;
   }
@@ -794,7 +793,8 @@
   memset(&tc->op, 0, sizeof(tc->op));
   tc->op.cancel_error = tc->error;
   /* reuse closure to catch completion */
-  grpc_closure_init(&tc->closure, done_termination, tc);
+  grpc_closure_init(&tc->closure, done_termination, tc,
+                    grpc_schedule_on_exec_ctx);
   tc->op.on_complete = &tc->closure;
   execute_op(exec_ctx, tc->call, &tc->op);
 }
@@ -804,23 +804,25 @@
   memset(&tc->op, 0, sizeof(tc->op));
   tc->op.close_error = tc->error;
   /* reuse closure to catch completion */
-  grpc_closure_init(&tc->closure, done_termination, tc);
+  grpc_closure_init(&tc->closure, done_termination, tc,
+                    grpc_schedule_on_exec_ctx);
   tc->op.on_complete = &tc->closure;
   execute_op(exec_ctx, tc->call, &tc->op);
 }
 
 static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
                                              termination_closure *tc) {
-  set_status_from_error(tc->call, STATUS_FROM_API_OVERRIDE, tc->error);
+  set_status_from_error(exec_ctx, tc->call, STATUS_FROM_API_OVERRIDE,
+                        tc->error);
 
   if (tc->type == TC_CANCEL) {
-    grpc_closure_init(&tc->closure, send_cancel, tc);
+    grpc_closure_init(&tc->closure, send_cancel, tc, grpc_schedule_on_exec_ctx);
     GRPC_CALL_INTERNAL_REF(tc->call, "cancel");
   } else if (tc->type == TC_CLOSE) {
-    grpc_closure_init(&tc->closure, send_close, tc);
+    grpc_closure_init(&tc->closure, send_close, tc, grpc_schedule_on_exec_ctx);
     GRPC_CALL_INTERNAL_REF(tc->call, "close");
   }
-  grpc_exec_ctx_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, &tc->closure, GRPC_ERROR_NONE);
   return GRPC_CALL_OK;
 }
 
@@ -928,7 +930,8 @@
   return algorithm;
 }
 
-static grpc_mdelem *recv_common_filter(grpc_call *call, grpc_mdelem *elem) {
+static grpc_mdelem *recv_common_filter(grpc_exec_ctx *exec_ctx, grpc_call *call,
+                                       grpc_mdelem *elem) {
   if (elem->key == GRPC_MDSTR_GRPC_STATUS) {
     GPR_TIMER_BEGIN("status", 0);
     set_status_code(call, STATUS_FROM_WIRE, decode_status(elem));
@@ -936,7 +939,8 @@
     return NULL;
   } else if (elem->key == GRPC_MDSTR_GRPC_MESSAGE) {
     GPR_TIMER_BEGIN("status-details", 0);
-    set_status_details(call, STATUS_FROM_WIRE, GRPC_MDSTR_REF(elem->value));
+    set_status_details(exec_ctx, call, STATUS_FROM_WIRE,
+                       GRPC_MDSTR_REF(elem->value));
     GPR_TIMER_END("status-details", 0);
     return NULL;
   }
@@ -962,9 +966,10 @@
   return elem;
 }
 
-static grpc_mdelem *recv_initial_filter(void *callp, grpc_mdelem *elem) {
-  grpc_call *call = callp;
-  elem = recv_common_filter(call, elem);
+static grpc_mdelem *recv_initial_filter(grpc_exec_ctx *exec_ctx, void *args,
+                                        grpc_mdelem *elem) {
+  grpc_call *call = args;
+  elem = recv_common_filter(exec_ctx, call, elem);
   if (elem == NULL) {
     return NULL;
   } else if (elem->key == GRPC_MDSTR_GRPC_ENCODING) {
@@ -974,7 +979,7 @@
     return NULL;
   } else if (elem->key == GRPC_MDSTR_GRPC_ACCEPT_ENCODING) {
     GPR_TIMER_BEGIN("encodings_accepted_by_peer", 0);
-    set_encodings_accepted_by_peer(call, elem);
+    set_encodings_accepted_by_peer(exec_ctx, call, elem);
     GPR_TIMER_END("encodings_accepted_by_peer", 0);
     return NULL;
   } else {
@@ -982,9 +987,10 @@
   }
 }
 
-static grpc_mdelem *recv_trailing_filter(void *callp, grpc_mdelem *elem) {
-  grpc_call *call = callp;
-  elem = recv_common_filter(call, elem);
+static grpc_mdelem *recv_trailing_filter(grpc_exec_ctx *exec_ctx, void *args,
+                                         grpc_mdelem *elem) {
+  grpc_call *call = args;
+  elem = recv_common_filter(exec_ctx, call, elem);
   if (elem == NULL) {
     return NULL;
   } else {
@@ -1138,8 +1144,8 @@
     } else {
       *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
     }
-    grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready,
-                      bctl);
+    grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready, bctl,
+                      grpc_schedule_on_exec_ctx);
     continue_receiving_slices(exec_ctx, bctl);
   }
 }
@@ -1234,7 +1240,7 @@
   if (error == GRPC_ERROR_NONE) {
     grpc_metadata_batch *md =
         &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
-    grpc_metadata_batch_filter(md, recv_initial_filter, call);
+    grpc_metadata_batch_filter(exec_ctx, md, recv_initial_filter, call);
 
     GPR_TIMER_BEGIN("validate_filtered_metadata", 0);
     validate_filtered_metadata(exec_ctx, bctl);
@@ -1251,9 +1257,10 @@
   call->has_initial_md_been_received = true;
   if (call->saved_receiving_stream_ready_bctlp != NULL) {
     grpc_closure *saved_rsr_closure = grpc_closure_create(
-        receiving_stream_ready, call->saved_receiving_stream_ready_bctlp);
+        receiving_stream_ready, call->saved_receiving_stream_ready_bctlp,
+        grpc_schedule_on_exec_ctx);
     call->saved_receiving_stream_ready_bctlp = NULL;
-    grpc_exec_ctx_sched(exec_ctx, saved_rsr_closure, error, NULL);
+    grpc_closure_sched(exec_ctx, saved_rsr_closure, error);
   }
 
   gpr_mu_unlock(&call->mu);
@@ -1278,14 +1285,15 @@
   intptr_t status;
   if (error != GRPC_ERROR_NONE &&
       grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) {
-    set_status_from_error(call, STATUS_FROM_CORE, error);
+    set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
   }
 
   if (bctl->send_initial_metadata) {
     if (error != GRPC_ERROR_NONE) {
-      set_status_from_error(call, STATUS_FROM_CORE, error);
+      set_status_from_error(exec_ctx, call, STATUS_FROM_CORE, error);
     }
     grpc_metadata_batch_destroy(
+        exec_ctx,
         &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */]);
   }
   if (bctl->send_message) {
@@ -1293,12 +1301,13 @@
   }
   if (bctl->send_final_op) {
     grpc_metadata_batch_destroy(
+        exec_ctx,
         &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
   }
   if (bctl->recv_final_op) {
     grpc_metadata_batch *md =
         &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-    grpc_metadata_batch_filter(md, recv_trailing_filter, call);
+    grpc_metadata_batch_filter(exec_ctx, md, recv_trailing_filter, call);
 
     call->received_final_op = true;
     /* propagate cancellation to any interested children */
@@ -1435,7 +1444,7 @@
         bctl->send_initial_metadata = 1;
         call->sent_initial_metadata = 1;
         if (!prepare_application_metadata(
-                call, (int)op->data.send_initial_metadata.count,
+                exec_ctx, call, (int)op->data.send_initial_metadata.count,
                 op->data.send_initial_metadata.metadata, 0, call->is_client,
                 &compression_md, (int)additional_metadata_count)) {
           error = GRPC_CALL_ERROR_INVALID_METADATA;
@@ -1515,15 +1524,15 @@
         call->sent_final_op = 1;
         call->send_extra_metadata_count = 1;
         call->send_extra_metadata[0].md = grpc_channel_get_reffed_status_elem(
-            call->channel, op->data.send_status_from_server.status);
+            exec_ctx, call->channel, op->data.send_status_from_server.status);
         if (op->data.send_status_from_server.status_details != NULL) {
           call->send_extra_metadata[1].md = grpc_mdelem_from_metadata_strings(
-              GRPC_MDSTR_GRPC_MESSAGE,
+              exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
               grpc_mdstr_from_string(
                   op->data.send_status_from_server.status_details));
           call->send_extra_metadata_count++;
           set_status_details(
-              call, STATUS_FROM_API_OVERRIDE,
+              exec_ctx, call, STATUS_FROM_API_OVERRIDE,
               GRPC_MDSTR_REF(call->send_extra_metadata[1].md->value));
         }
         if (op->data.send_status_from_server.status != GRPC_STATUS_OK) {
@@ -1531,7 +1540,7 @@
                           (uint32_t)op->data.send_status_from_server.status);
         }
         if (!prepare_application_metadata(
-                call,
+                exec_ctx, call,
                 (int)op->data.send_status_from_server.trailing_metadata_count,
                 op->data.send_status_from_server.trailing_metadata, 1, 1, NULL,
                 0)) {
@@ -1558,7 +1567,8 @@
         call->received_initial_metadata = 1;
         call->buffered_metadata[0] = op->data.recv_initial_metadata;
         grpc_closure_init(&call->receiving_initial_metadata_ready,
-                          receiving_initial_metadata_ready, bctl);
+                          receiving_initial_metadata_ready, bctl,
+                          grpc_schedule_on_exec_ctx);
         bctl->recv_initial_metadata = 1;
         stream_op->recv_initial_metadata =
             &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
@@ -1581,7 +1591,7 @@
         call->receiving_buffer = op->data.recv_message;
         stream_op->recv_message = &call->receiving_stream;
         grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
-                          bctl);
+                          bctl, grpc_schedule_on_exec_ctx);
         stream_op->recv_message_ready = &call->receiving_stream_ready;
         num_completion_callbacks_needed++;
         break;
@@ -1646,7 +1656,8 @@
   gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
 
   stream_op->context = call->context;
-  grpc_closure_init(&bctl->finish_batch, finish_batch, bctl);
+  grpc_closure_init(&bctl->finish_batch, finish_batch, bctl,
+                    grpc_schedule_on_exec_ctx);
   stream_op->on_complete = &bctl->finish_batch;
   gpr_mu_unlock(&call->mu);
 
@@ -1660,7 +1671,7 @@
   /* reverse any mutations that occured */
   if (bctl->send_initial_metadata) {
     call->sent_initial_metadata = 0;
-    grpc_metadata_batch_clear(&call->metadata_batch[0][0]);
+    grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][0]);
   }
   if (bctl->send_message) {
     call->sending_message = 0;
@@ -1668,7 +1679,7 @@
   }
   if (bctl->send_final_op) {
     call->sent_final_op = 0;
-    grpc_metadata_batch_clear(&call->metadata_batch[0][1]);
+    grpc_metadata_batch_clear(exec_ctx, &call->metadata_batch[0][1]);
   }
   if (bctl->recv_initial_metadata) {
     call->received_initial_metadata = 0;
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 18af41b..233340c 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -70,7 +70,8 @@
 /* Create a new call based on \a args.
    Regardless of success or failure, always returns a valid new call into *call
    */
-grpc_error *grpc_call_create(const grpc_call_create_args *args,
+grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
+                             const grpc_call_create_args *args,
                              grpc_call **call);
 
 void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index 1389df6..b872957 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -86,87 +86,91 @@
                                   const grpc_channel_args *input_args,
                                   grpc_channel_stack_type channel_stack_type,
                                   grpc_transport *optional_transport) {
-  bool is_client = grpc_channel_stack_type_is_client(channel_stack_type);
-
   grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create();
-  grpc_channel_stack_builder_set_channel_arguments(builder, input_args);
+  grpc_channel_stack_builder_set_channel_arguments(exec_ctx, builder,
+                                                   input_args);
   grpc_channel_stack_builder_set_target(builder, target);
   grpc_channel_stack_builder_set_transport(builder, optional_transport);
-  grpc_channel *channel;
-  grpc_channel_args *args;
   if (!grpc_channel_init_create_stack(exec_ctx, builder, channel_stack_type)) {
-    grpc_channel_stack_builder_destroy(builder);
+    grpc_channel_stack_builder_destroy(exec_ctx, builder);
     return NULL;
-  } else {
-    args = grpc_channel_args_copy(
-        grpc_channel_stack_builder_get_channel_arguments(builder));
-    channel = grpc_channel_stack_builder_finish(
-        exec_ctx, builder, sizeof(grpc_channel), 1, destroy_channel, NULL);
+  }
+  grpc_channel_args *args = grpc_channel_args_copy(
+      grpc_channel_stack_builder_get_channel_arguments(builder));
+  grpc_channel *channel;
+  grpc_error *error = grpc_channel_stack_builder_finish(
+      exec_ctx, builder, sizeof(grpc_channel), 1, destroy_channel, NULL,
+      (void **)&channel);
+  if (error != GRPC_ERROR_NONE) {
+    const char *msg = grpc_error_string(error);
+    gpr_log(GPR_ERROR, "channel stack builder failed: %s", msg);
+    grpc_error_free_string(msg);
+    GRPC_ERROR_UNREF(error);
+    goto done;
   }
 
   memset(channel, 0, sizeof(*channel));
   channel->target = gpr_strdup(target);
-  channel->is_client = is_client;
+  channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
   gpr_mu_init(&channel->registered_call_mu);
   channel->registered_calls = NULL;
 
   grpc_compression_options_init(&channel->compression_options);
-  if (args) {
-    for (size_t i = 0; i < args->num_args; i++) {
-      if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
-        if (args->args[i].type != GRPC_ARG_STRING) {
-          gpr_log(GPR_ERROR, "%s ignored: it must be a string",
-                  GRPC_ARG_DEFAULT_AUTHORITY);
-        } else {
-          if (channel->default_authority) {
-            /* setting this takes precedence over anything else */
-            GRPC_MDELEM_UNREF(channel->default_authority);
-          }
-          channel->default_authority = grpc_mdelem_from_strings(
-              ":authority", args->args[i].value.string);
+
+  for (size_t i = 0; i < args->num_args; i++) {
+    if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
+      if (args->args[i].type != GRPC_ARG_STRING) {
+        gpr_log(GPR_ERROR, "%s ignored: it must be a string",
+                GRPC_ARG_DEFAULT_AUTHORITY);
+      } else {
+        if (channel->default_authority) {
+          /* setting this takes precedence over anything else */
+          GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
         }
-      } else if (0 ==
-                 strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
-        if (args->args[i].type != GRPC_ARG_STRING) {
-          gpr_log(GPR_ERROR, "%s ignored: it must be a string",
+        channel->default_authority = grpc_mdelem_from_strings(
+            exec_ctx, ":authority", args->args[i].value.string);
+      }
+    } else if (0 ==
+               strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
+      if (args->args[i].type != GRPC_ARG_STRING) {
+        gpr_log(GPR_ERROR, "%s ignored: it must be a string",
+                GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
+      } else {
+        if (channel->default_authority) {
+          /* other ways of setting this (notably ssl) take precedence */
+          gpr_log(GPR_ERROR,
+                  "%s ignored: default host already set some other way",
                   GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
         } else {
-          if (channel->default_authority) {
-            /* other ways of setting this (notably ssl) take precedence */
-            gpr_log(GPR_ERROR,
-                    "%s ignored: default host already set some other way",
-                    GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
-          } else {
-            channel->default_authority = grpc_mdelem_from_strings(
-                ":authority", args->args[i].value.string);
-          }
+          channel->default_authority = grpc_mdelem_from_strings(
+              exec_ctx, ":authority", args->args[i].value.string);
         }
-      } else if (0 == strcmp(args->args[i].key,
-                             GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
-        channel->compression_options.default_level.is_set = true;
-        GPR_ASSERT(args->args[i].value.integer >= 0 &&
-                   args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT);
-        channel->compression_options.default_level.level =
-            (grpc_compression_level)args->args[i].value.integer;
-      } else if (0 == strcmp(args->args[i].key,
-                             GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
-        channel->compression_options.default_algorithm.is_set = true;
-        GPR_ASSERT(args->args[i].value.integer >= 0 &&
-                   args->args[i].value.integer <
-                       GRPC_COMPRESS_ALGORITHMS_COUNT);
-        channel->compression_options.default_algorithm.algorithm =
-            (grpc_compression_algorithm)args->args[i].value.integer;
-      } else if (0 ==
-                 strcmp(args->args[i].key,
-                        GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
-        channel->compression_options.enabled_algorithms_bitset =
-            (uint32_t)args->args[i].value.integer |
-            0x1; /* always support no compression */
       }
+    } else if (0 == strcmp(args->args[i].key,
+                           GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
+      channel->compression_options.default_level.is_set = true;
+      GPR_ASSERT(args->args[i].value.integer >= 0 &&
+                 args->args[i].value.integer < GRPC_COMPRESS_LEVEL_COUNT);
+      channel->compression_options.default_level.level =
+          (grpc_compression_level)args->args[i].value.integer;
+    } else if (0 == strcmp(args->args[i].key,
+                           GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
+      channel->compression_options.default_algorithm.is_set = true;
+      GPR_ASSERT(args->args[i].value.integer >= 0 &&
+                 args->args[i].value.integer < GRPC_COMPRESS_ALGORITHMS_COUNT);
+      channel->compression_options.default_algorithm.algorithm =
+          (grpc_compression_algorithm)args->args[i].value.integer;
+    } else if (0 ==
+               strcmp(args->args[i].key,
+                      GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
+      channel->compression_options.enabled_algorithms_bitset =
+          (uint32_t)args->args[i].value.integer |
+          0x1; /* always support no compression */
     }
-    grpc_channel_args_destroy(args);
   }
 
+done:
+  grpc_channel_args_destroy(exec_ctx, args);
   return channel;
 }
 
@@ -185,10 +189,10 @@
 }
 
 static grpc_call *grpc_channel_create_call_internal(
-    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
-    grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
-    grpc_mdelem *path_mdelem, grpc_mdelem *authority_mdelem,
-    gpr_timespec deadline) {
+    grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
+    uint32_t propagation_mask, grpc_completion_queue *cq,
+    grpc_pollset_set *pollset_set_alternative, grpc_mdelem *path_mdelem,
+    grpc_mdelem *authority_mdelem, gpr_timespec deadline) {
   grpc_mdelem *send_metadata[2];
   size_t num_metadata = 0;
 
@@ -215,7 +219,7 @@
   args.send_deadline = deadline;
 
   grpc_call *call;
-  GRPC_LOG_IF_ERROR("call_create", grpc_call_create(&args, &call));
+  GRPC_LOG_IF_ERROR("call_create", grpc_call_create(exec_ctx, &args, &call));
   return call;
 }
 
@@ -236,26 +240,30 @@
       (channel, parent_call, (unsigned)propagation_mask, cq, method, host,
        deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, reserved));
   GPR_ASSERT(!reserved);
-  return grpc_channel_create_call_internal(
-      channel, parent_call, propagation_mask, cq, NULL,
-      grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_call *call = grpc_channel_create_call_internal(
+      &exec_ctx, channel, parent_call, propagation_mask, cq, NULL,
+      grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_PATH,
                                         grpc_mdstr_from_string(method)),
-      host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
+      host ? grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_AUTHORITY,
                                                grpc_mdstr_from_string(host))
            : NULL,
       deadline);
+  grpc_exec_ctx_finish(&exec_ctx);
+  return call;
 }
 
 grpc_call *grpc_channel_create_pollset_set_call(
-    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
-    grpc_pollset_set *pollset_set, const char *method, const char *host,
-    gpr_timespec deadline, void *reserved) {
+    grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
+    uint32_t propagation_mask, grpc_pollset_set *pollset_set,
+    const char *method, const char *host, gpr_timespec deadline,
+    void *reserved) {
   GPR_ASSERT(!reserved);
   return grpc_channel_create_call_internal(
-      channel, parent_call, propagation_mask, NULL, pollset_set,
-      grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+      exec_ctx, channel, parent_call, propagation_mask, NULL, pollset_set,
+      grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_PATH,
                                         grpc_mdstr_from_string(method)),
-      host ? grpc_mdelem_from_metadata_strings(GRPC_MDSTR_AUTHORITY,
+      host ? grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_AUTHORITY,
                                                grpc_mdstr_from_string(host))
            : NULL,
       deadline);
@@ -268,15 +276,18 @@
       "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
       4, (channel, method, host, reserved));
   GPR_ASSERT(!reserved);
-  rc->path = grpc_mdelem_from_metadata_strings(GRPC_MDSTR_PATH,
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  rc->path = grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_PATH,
                                                grpc_mdstr_from_string(method));
-  rc->authority = host ? grpc_mdelem_from_metadata_strings(
-                             GRPC_MDSTR_AUTHORITY, grpc_mdstr_from_string(host))
-                       : NULL;
+  rc->authority =
+      host ? grpc_mdelem_from_metadata_strings(&exec_ctx, GRPC_MDSTR_AUTHORITY,
+                                               grpc_mdstr_from_string(host))
+           : NULL;
   gpr_mu_lock(&channel->registered_call_mu);
   rc->next = channel->registered_calls;
   channel->registered_calls = rc;
   gpr_mu_unlock(&channel->registered_call_mu);
+  grpc_exec_ctx_finish(&exec_ctx);
   return rc;
 }
 
@@ -296,10 +307,13 @@
           registered_call_handle, deadline.tv_sec, deadline.tv_nsec,
           (int)deadline.clock_type, reserved));
   GPR_ASSERT(!reserved);
-  return grpc_channel_create_call_internal(
-      channel, parent_call, propagation_mask, completion_queue, NULL,
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_call *call = grpc_channel_create_call_internal(
+      &exec_ctx, channel, parent_call, propagation_mask, completion_queue, NULL,
       GRPC_MDELEM_REF(rc->path),
       rc->authority ? GRPC_MDELEM_REF(rc->authority) : NULL, deadline);
+  grpc_exec_ctx_finish(&exec_ctx);
+  return call;
 }
 
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
@@ -325,14 +339,14 @@
   while (channel->registered_calls) {
     registered_call *rc = channel->registered_calls;
     channel->registered_calls = rc->next;
-    GRPC_MDELEM_UNREF(rc->path);
+    GRPC_MDELEM_UNREF(exec_ctx, rc->path);
     if (rc->authority) {
-      GRPC_MDELEM_UNREF(rc->authority);
+      GRPC_MDELEM_UNREF(exec_ctx, rc->authority);
     }
     gpr_free(rc);
   }
   if (channel->default_authority != NULL) {
-    GRPC_MDELEM_UNREF(channel->default_authority);
+    GRPC_MDELEM_UNREF(exec_ctx, channel->default_authority);
   }
   gpr_mu_destroy(&channel->registered_call_mu);
   gpr_free(channel->target);
@@ -362,7 +376,8 @@
   return channel->compression_options;
 }
 
-grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel, int i) {
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
+                                                 grpc_channel *channel, int i) {
   char tmp[GPR_LTOA_MIN_BUFSIZE];
   switch (i) {
     case 0:
@@ -373,6 +388,6 @@
       return GRPC_MDELEM_GRPC_STATUS_2;
   }
   gpr_ltoa(i, tmp);
-  return grpc_mdelem_from_metadata_strings(GRPC_MDSTR_GRPC_STATUS,
+  return grpc_mdelem_from_metadata_strings(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
                                            grpc_mdstr_from_string(tmp));
 }
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 23cc865..2ebadb7 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -51,9 +51,10 @@
     properties from the server call to this new client call, depending on the
     value of \a propagation_mask (see propagation_bits.h for possible values) */
 grpc_call *grpc_channel_create_pollset_set_call(
-    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
-    grpc_pollset_set *pollset_set, const char *method, const char *host,
-    gpr_timespec deadline, void *reserved);
+    grpc_exec_ctx *exec_ctx, grpc_channel *channel, grpc_call *parent_call,
+    uint32_t propagation_mask, grpc_pollset_set *pollset_set,
+    const char *method, const char *host, gpr_timespec deadline,
+    void *reserved);
 
 /** Get a (borrowed) pointer to this channels underlying channel stack */
 grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel);
@@ -62,7 +63,8 @@
     status_code.
 
     The returned elem is owned by the caller. */
-grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_channel *channel,
+grpc_mdelem *grpc_channel_get_reffed_status_elem(grpc_exec_ctx *exec_ctx,
+                                                 grpc_channel *channel,
                                                  int status_code);
 
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
diff --git a/src/core/lib/surface/channel_init.c b/src/core/lib/surface/channel_init.c
index 0627b34..7acb444 100644
--- a/src/core/lib/surface/channel_init.c
+++ b/src/core/lib/surface/channel_init.c
@@ -131,7 +131,7 @@
 
   for (size_t i = 0; i < g_slots[type].num_slots; i++) {
     const stage_slot *slot = &g_slots[type].slots[i];
-    if (!slot->fn(builder, slot->arg)) {
+    if (!slot->fn(exec_ctx, builder, slot->arg)) {
       return false;
     }
   }
diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h
index b53f2ae..411f5ea 100644
--- a/src/core/lib/surface/channel_init.h
+++ b/src/core/lib/surface/channel_init.h
@@ -51,7 +51,8 @@
 
 /// One stage of mutation: call functions against \a builder to influence the
 /// finally constructed channel stack
-typedef bool (*grpc_channel_init_stage)(grpc_channel_stack_builder *builder,
+typedef bool (*grpc_channel_init_stage)(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_stack_builder *builder,
                                         void *arg);
 
 /// Global initialization of the system
diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c
index 0d2f01a..e68febd 100644
--- a/src/core/lib/surface/channel_ping.c
+++ b/src/core/lib/surface/channel_ping.c
@@ -71,7 +71,7 @@
   GPR_ASSERT(reserved == NULL);
   pr->tag = tag;
   pr->cq = cq;
-  grpc_closure_init(&pr->closure, ping_done, pr);
+  grpc_closure_init(&pr->closure, ping_done, pr, grpc_schedule_on_exec_ctx);
   op->send_ping = &pr->closure;
   op->bind_pollset = grpc_cq_pollset(cq);
   grpc_cq_begin_op(cq, tag);
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 184c1a1..4613c90 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -168,7 +168,8 @@
 #ifndef NDEBUG
   cc->outstanding_tag_count = 0;
 #endif
-  grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc);
+  grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc,
+                    grpc_schedule_on_exec_ctx);
 
   GPR_TIMER_END("grpc_completion_queue_create", 0);
 
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 7903f57..f61bf15 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -44,6 +44,7 @@
 #include "src/core/lib/channel/compress_filter.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/channel/deadline_filter.h"
+#include "src/core/lib/channel/handshaker_registry.h"
 #include "src/core/lib/channel/http_client_filter.h"
 #include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/channel/message_size_filter.h"
@@ -80,17 +81,20 @@
   g_initializations = 0;
 }
 
-static bool append_filter(grpc_channel_stack_builder *builder, void *arg) {
+static bool append_filter(grpc_exec_ctx *exec_ctx,
+                          grpc_channel_stack_builder *builder, void *arg) {
   return grpc_channel_stack_builder_append_filter(
       builder, (const grpc_channel_filter *)arg, NULL, NULL);
 }
 
-static bool prepend_filter(grpc_channel_stack_builder *builder, void *arg) {
+static bool prepend_filter(grpc_exec_ctx *exec_ctx,
+                           grpc_channel_stack_builder *builder, void *arg) {
   return grpc_channel_stack_builder_prepend_filter(
       builder, (const grpc_channel_filter *)arg, NULL, NULL);
 }
 
-static bool maybe_add_http_filter(grpc_channel_stack_builder *builder,
+static bool maybe_add_http_filter(grpc_exec_ctx *exec_ctx,
+                                  grpc_channel_stack_builder *builder,
                                   void *arg) {
   grpc_transport *t = grpc_channel_stack_builder_get_transport(builder);
   if (t && strstr(t->vtable->name, "http")) {
@@ -201,6 +205,8 @@
     grpc_executor_init();
     gpr_timers_global_init();
     grpc_cq_global_init();
+    grpc_handshaker_factory_registry_init();
+    grpc_security_init();
     for (i = 0; i < g_number_of_plugins; i++) {
       if (g_all_of_the_plugins[i].init != NULL) {
         g_all_of_the_plugins[i].init();
@@ -221,11 +227,12 @@
 void grpc_shutdown(void) {
   int i;
   GRPC_API_TRACE("grpc_shutdown(void)", 0, ());
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   gpr_mu_lock(&g_init_mu);
   if (--g_initializations == 0) {
-    grpc_executor_shutdown();
+    grpc_executor_shutdown(&exec_ctx);
     grpc_cq_global_shutdown();
-    grpc_iomgr_shutdown();
+    grpc_iomgr_shutdown(&exec_ctx);
     gpr_timers_global_destroy();
     grpc_tracer_shutdown();
     for (i = g_number_of_plugins; i >= 0; i--) {
@@ -233,9 +240,11 @@
         g_all_of_the_plugins[i].destroy();
       }
     }
-    grpc_mdctx_global_shutdown();
+    grpc_mdctx_global_shutdown(&exec_ctx);
+    grpc_handshaker_factory_registry_shutdown(&exec_ctx);
   }
   gpr_mu_unlock(&g_init_mu);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int grpc_is_initialized(void) {
diff --git a/src/core/lib/surface/init.h b/src/core/lib/surface/init.h
index b1bf57c..3d1c528 100644
--- a/src/core/lib/surface/init.h
+++ b/src/core/lib/surface/init.h
@@ -36,6 +36,7 @@
 
 void grpc_register_security_filters(void);
 void grpc_security_pre_init(void);
+void grpc_security_init(void);
 int grpc_is_initialized(void);
 
 #endif /* GRPC_CORE_LIB_SURFACE_INIT_H */
diff --git a/src/core/lib/surface/init_secure.c b/src/core/lib/surface/init_secure.c
index 7ee7b51..a44407d 100644
--- a/src/core/lib/surface/init_secure.c
+++ b/src/core/lib/surface/init_secure.c
@@ -41,6 +41,7 @@
 #include "src/core/lib/security/transport/auth_filters.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
 #include "src/core/lib/security/transport/security_connector.h"
+#include "src/core/lib/security/transport/security_handshaker.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/tsi/transport_security_interface.h"
 
@@ -50,7 +51,7 @@
 }
 
 static bool maybe_prepend_client_auth_filter(
-    grpc_channel_stack_builder *builder, void *arg) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) {
   const grpc_channel_args *args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
   if (args) {
@@ -65,7 +66,7 @@
 }
 
 static bool maybe_prepend_server_auth_filter(
-    grpc_channel_stack_builder *builder, void *arg) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) {
   const grpc_channel_args *args =
       grpc_channel_stack_builder_get_channel_arguments(builder);
   if (args) {
@@ -87,3 +88,5 @@
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
                                    maybe_prepend_server_auth_filter, NULL);
 }
+
+void grpc_security_init() { grpc_security_register_handshaker_factories(); }
diff --git a/src/core/lib/surface/init_unsecure.c b/src/core/lib/surface/init_unsecure.c
index f952739..dbc9223 100644
--- a/src/core/lib/surface/init_unsecure.c
+++ b/src/core/lib/surface/init_unsecure.c
@@ -36,3 +36,5 @@
 void grpc_security_pre_init(void) {}
 
 void grpc_register_security_filters(void) {}
+
+void grpc_security_init(void) {}
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index d0df8e7..ae1eac0 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -55,14 +55,15 @@
   const char *error_message;
 } channel_data;
 
-static void fill_metadata(grpc_call_element *elem, grpc_metadata_batch *mdb) {
+static void fill_metadata(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                          grpc_metadata_batch *mdb) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   char tmp[GPR_LTOA_MIN_BUFSIZE];
   gpr_ltoa(chand->error_code, tmp);
-  calld->status.md = grpc_mdelem_from_strings("grpc-status", tmp);
+  calld->status.md = grpc_mdelem_from_strings(exec_ctx, "grpc-status", tmp);
   calld->details.md =
-      grpc_mdelem_from_strings("grpc-message", chand->error_message);
+      grpc_mdelem_from_strings(exec_ctx, "grpc-message", chand->error_message);
   calld->status.prev = calld->details.next = NULL;
   calld->status.next = &calld->details;
   calld->details.prev = &calld->status;
@@ -76,9 +77,9 @@
                                            grpc_transport_stream_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   if (op->recv_initial_metadata != NULL) {
-    fill_metadata(elem, op->recv_initial_metadata);
+    fill_metadata(exec_ctx, elem, op->recv_initial_metadata);
   } else if (op->recv_trailing_metadata != NULL) {
-    fill_metadata(elem, op->recv_trailing_metadata);
+    fill_metadata(exec_ctx, elem, op->recv_trailing_metadata);
   }
   grpc_transport_stream_op_finish_with_failure(
       exec_ctx, op, GRPC_ERROR_CREATE("lame client channel"));
@@ -98,16 +99,16 @@
   if (op->on_connectivity_state_change) {
     GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_SHUTDOWN);
     *op->connectivity_state = GRPC_CHANNEL_SHUTDOWN;
-    grpc_exec_ctx_sched(exec_ctx, op->on_connectivity_state_change,
-                        GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, op->on_connectivity_state_change,
+                       GRPC_ERROR_NONE);
   }
   if (op->send_ping != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, op->send_ping,
-                        GRPC_ERROR_CREATE("lame client channel"), NULL);
+    grpc_closure_sched(exec_ctx, op->send_ping,
+                       GRPC_ERROR_CREATE("lame client channel"));
   }
   GRPC_ERROR_UNREF(op->disconnect_with_error);
   if (op->on_consumed != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
   }
 }
 
@@ -123,11 +124,12 @@
   gpr_free(and_free_memory);
 }
 
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(args->is_last);
+  return GRPC_ERROR_NONE;
 }
 
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index fe73aa3..addb7c4 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -45,6 +45,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/stack_lockfree.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -271,14 +272,15 @@
 static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
                              grpc_error *error) {
   struct shutdown_cleanup_args *a = arg;
-  grpc_slice_unref(a->slice);
+  grpc_slice_unref_internal(exec_ctx, a->slice);
   gpr_free(a);
 }
 
 static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
                           int send_goaway, grpc_error *send_disconnect) {
   struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc));
-  grpc_closure_init(&sc->closure, shutdown_cleanup, sc);
+  grpc_closure_init(&sc->closure, shutdown_cleanup, sc,
+                    grpc_schedule_on_exec_ctx);
   grpc_transport_op *op = grpc_make_transport_op(&sc->closure);
   grpc_channel_element *elem;
 
@@ -346,9 +348,9 @@
     gpr_mu_unlock(&calld->mu_state);
     grpc_closure_init(
         &calld->kill_zombie_closure, kill_zombie,
-        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-    grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE,
-                        NULL);
+        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0),
+        grpc_schedule_on_exec_ctx);
+    grpc_closure_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE);
   }
 }
 
@@ -379,7 +381,7 @@
 static void server_delete(grpc_exec_ctx *exec_ctx, grpc_server *server) {
   registered_method *rm;
   size_t i;
-  grpc_channel_args_destroy(server->channel_args);
+  grpc_channel_args_destroy(exec_ctx, server->channel_args);
   gpr_mu_destroy(&server->mu_global);
   gpr_mu_destroy(&server->mu_call);
   while ((rm = server->registered_methods) != NULL) {
@@ -440,8 +442,8 @@
   orphan_channel(chand);
   server_ref(chand->server);
   maybe_finish_shutdown(exec_ctx, chand->server);
-  chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
-  chand->finish_destroy_channel_closure.cb_arg = chand;
+  grpc_closure_init(&chand->finish_destroy_channel_closure,
+                    finish_destroy_channel, chand, grpc_schedule_on_exec_ctx);
 
   if (grpc_server_channel_trace && error != GRPC_ERROR_NONE) {
     const char *msg = grpc_error_string(error);
@@ -545,8 +547,9 @@
     gpr_mu_unlock(&calld->mu_state);
     grpc_closure_init(
         &calld->kill_zombie_closure, kill_zombie,
-        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-    grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, error, NULL);
+        grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0),
+        grpc_schedule_on_exec_ctx);
+    grpc_closure_sched(exec_ctx, &calld->kill_zombie_closure, error);
     return;
   }
 
@@ -590,9 +593,9 @@
     gpr_mu_lock(&calld->mu_state);
     calld->state = ZOMBIED;
     gpr_mu_unlock(&calld->mu_state);
-    grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-    grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE,
-                        NULL);
+    grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem,
+                      grpc_schedule_on_exec_ctx);
+    grpc_closure_sched(exec_ctx, &calld->kill_zombie_closure, GRPC_ERROR_NONE);
     return;
   }
 
@@ -607,7 +610,8 @@
       memset(&op, 0, sizeof(op));
       op.op = GRPC_OP_RECV_MESSAGE;
       op.data.recv_message = &calld->payload;
-      grpc_closure_init(&calld->publish, publish_new_rpc, elem);
+      grpc_closure_init(&calld->publish, publish_new_rpc, elem,
+                        grpc_schedule_on_exec_ctx);
       grpc_call_start_batch_and_execute(exec_ctx, calld->call, &op, 1,
                                         &calld->publish);
       break;
@@ -740,7 +744,8 @@
   }
 }
 
-static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
+static grpc_mdelem *server_filter(grpc_exec_ctx *exec_ctx, void *user_data,
+                                  grpc_mdelem *md) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   if (md->key == GRPC_MDSTR_PATH) {
@@ -764,7 +769,8 @@
   gpr_timespec op_deadline;
 
   GRPC_ERROR_REF(error);
-  grpc_metadata_batch_filter(calld->recv_initial_metadata, server_filter, elem);
+  grpc_metadata_batch_filter(exec_ctx, calld->recv_initial_metadata,
+                             server_filter, elem);
   op_deadline = calld->recv_initial_metadata->deadline;
   if (0 != gpr_time_cmp(op_deadline, gpr_inf_future(op_deadline.clock_type))) {
     calld->deadline = op_deadline;
@@ -813,9 +819,10 @@
     if (calld->state == NOT_STARTED) {
       calld->state = ZOMBIED;
       gpr_mu_unlock(&calld->mu_state);
-      grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-      grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure,
-                          GRPC_ERROR_NONE, NULL);
+      grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem,
+                        grpc_schedule_on_exec_ctx);
+      grpc_closure_sched(exec_ctx, &calld->kill_zombie_closure,
+                         GRPC_ERROR_NONE);
     } else if (calld->state == PENDING) {
       calld->state = ZOMBIED;
       gpr_mu_unlock(&calld->mu_state);
@@ -838,7 +845,7 @@
   args.server_transport_data = transport_server_data;
   args.send_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
   grpc_call *call;
-  grpc_error *error = grpc_call_create(&args, &call);
+  grpc_error *error = grpc_call_create(exec_ctx, &args, &call);
   grpc_call_element *elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
   if (error != GRPC_ERROR_NONE) {
@@ -851,7 +858,8 @@
   memset(&op, 0, sizeof(op));
   op.op = GRPC_OP_RECV_INITIAL_METADATA;
   op.data.recv_initial_metadata = &calld->initial_metadata;
-  grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem);
+  grpc_closure_init(&calld->got_initial_metadata, got_initial_metadata, elem,
+                    grpc_schedule_on_exec_ctx);
   grpc_call_start_batch_and_execute(exec_ctx, call, &op, 1,
                                     &calld->got_initial_metadata);
 }
@@ -887,7 +895,8 @@
   gpr_mu_init(&calld->mu_state);
 
   grpc_closure_init(&calld->server_on_recv_initial_metadata,
-                    server_on_recv_initial_metadata, elem);
+                    server_on_recv_initial_metadata, elem,
+                    grpc_schedule_on_exec_ctx);
 
   server_ref(chand->server);
   return GRPC_ERROR_NONE;
@@ -902,10 +911,10 @@
   GPR_ASSERT(calld->state != PENDING);
 
   if (calld->host) {
-    GRPC_MDSTR_UNREF(calld->host);
+    GRPC_MDSTR_UNREF(exec_ctx, calld->host);
   }
   if (calld->path) {
-    GRPC_MDSTR_UNREF(calld->path);
+    GRPC_MDSTR_UNREF(exec_ctx, calld->path);
   }
   grpc_metadata_array_destroy(&calld->initial_metadata);
 
@@ -914,9 +923,9 @@
   server_unref(exec_ctx, chand->server);
 }
 
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(!args->is_last);
@@ -926,7 +935,9 @@
   chand->registered_methods = NULL;
   chand->connectivity_state = GRPC_CHANNEL_IDLE;
   grpc_closure_init(&chand->channel_connectivity_changed,
-                    channel_connectivity_changed, chand);
+                    channel_connectivity_changed, chand,
+                    grpc_schedule_on_exec_ctx);
+  return GRPC_ERROR_NONE;
 }
 
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
@@ -936,10 +947,10 @@
   if (chand->registered_methods) {
     for (i = 0; i < chand->registered_method_slots; i++) {
       if (chand->registered_methods[i].method) {
-        GRPC_MDSTR_UNREF(chand->registered_methods[i].method);
+        GRPC_MDSTR_UNREF(exec_ctx, chand->registered_methods[i].method);
       }
       if (chand->registered_methods[i].host) {
-        GRPC_MDSTR_UNREF(chand->registered_methods[i].host);
+        GRPC_MDSTR_UNREF(exec_ctx, chand->registered_methods[i].host);
       }
     }
     gpr_free(chand->registered_methods);
@@ -1277,7 +1288,8 @@
 
   /* Shutdown listeners */
   for (l = server->listeners; l; l = l->next) {
-    grpc_closure_init(&l->destroy_done, listener_destroy_done, server);
+    grpc_closure_init(&l->destroy_done, listener_destroy_done, server,
+                      grpc_schedule_on_exec_ctx);
     l->destroy(&exec_ctx, server, l->arg, &l->destroy_done);
   }
 
@@ -1383,9 +1395,10 @@
         gpr_mu_unlock(&calld->mu_state);
         grpc_closure_init(
             &calld->kill_zombie_closure, kill_zombie,
-            grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-        grpc_exec_ctx_sched(exec_ctx, &calld->kill_zombie_closure,
-                            GRPC_ERROR_NONE, NULL);
+            grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0),
+            grpc_schedule_on_exec_ctx);
+        grpc_closure_sched(exec_ctx, &calld->kill_zombie_closure,
+                           GRPC_ERROR_NONE);
       } else {
         GPR_ASSERT(calld->state == PENDING);
         calld->state = ACTIVATED;
diff --git a/src/core/lib/surface/validate_metadata.c b/src/core/lib/surface/validate_metadata.c
index 84f0a08..f49dd85 100644
--- a/src/core/lib/surface/validate_metadata.c
+++ b/src/core/lib/surface/validate_metadata.c
@@ -53,7 +53,7 @@
       0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0x03, 0x00, 0x00, 0x00,
       0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-  if (length == 0) {
+  if (length == 0 || key[0] == ':') {
     return 0;
   }
   return conforms_to(key, length, legal_header_bits);
diff --git a/src/core/lib/transport/README.md b/src/core/lib/transport/README.md
new file mode 100644
index 0000000..e7e135e
--- /dev/null
+++ b/src/core/lib/transport/README.md
@@ -0,0 +1,7 @@
+# Transport
+
+Common implementation details for gRPC Transports.
+
+Transports multiplex messages across some single connection. In ext/ there are
+implementations atop [a custom http2 implementation](/src/core/ext/transport/chttp2/README.md)
+and atop [cronet](/src/core/ext/transport/cronet/README.md).
diff --git a/src/core/lib/transport/byte_stream.c b/src/core/lib/transport/byte_stream.c
index 2f1d7b7..4d42061 100644
--- a/src/core/lib/transport/byte_stream.c
+++ b/src/core/lib/transport/byte_stream.c
@@ -37,6 +37,8 @@
 
 #include <grpc/support/log.h>
 
+#include "src/core/lib/slice/slice_internal.h"
+
 int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
                           grpc_byte_stream *byte_stream, grpc_slice *slice,
                           size_t max_size_hint, grpc_closure *on_complete) {
@@ -57,7 +59,8 @@
                                     grpc_closure *on_complete) {
   grpc_slice_buffer_stream *stream = (grpc_slice_buffer_stream *)byte_stream;
   GPR_ASSERT(stream->cursor < stream->backing_buffer->count);
-  *slice = grpc_slice_ref(stream->backing_buffer->slices[stream->cursor]);
+  *slice =
+      grpc_slice_ref_internal(stream->backing_buffer->slices[stream->cursor]);
   stream->cursor++;
   return 1;
 }
diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c
index 4f49d7c..c656d93 100644
--- a/src/core/lib/transport/connectivity_state.c
+++ b/src/core/lib/transport/connectivity_state.c
@@ -81,7 +81,7 @@
     } else {
       error = GRPC_ERROR_CREATE("Shutdown connectivity owner");
     }
-    grpc_exec_ctx_sched(exec_ctx, w->notify, error, NULL);
+    grpc_closure_sched(exec_ctx, w->notify, error);
     gpr_free(w);
   }
   GRPC_ERROR_UNREF(tracker->current_error);
@@ -121,7 +121,7 @@
   if (current == NULL) {
     grpc_connectivity_state_watcher *w = tracker->watchers;
     if (w != NULL && w->notify == notify) {
-      grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
+      grpc_closure_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED);
       tracker->watchers = w->next;
       gpr_free(w);
       return false;
@@ -129,7 +129,7 @@
     while (w != NULL) {
       grpc_connectivity_state_watcher *rm_candidate = w->next;
       if (rm_candidate != NULL && rm_candidate->notify == notify) {
-        grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED, NULL);
+        grpc_closure_sched(exec_ctx, notify, GRPC_ERROR_CANCELLED);
         w->next = w->next->next;
         gpr_free(rm_candidate);
         return false;
@@ -140,8 +140,8 @@
   } else {
     if (tracker->current_state != *current) {
       *current = tracker->current_state;
-      grpc_exec_ctx_sched(exec_ctx, notify,
-                          GRPC_ERROR_REF(tracker->current_error), NULL);
+      grpc_closure_sched(exec_ctx, notify,
+                         GRPC_ERROR_REF(tracker->current_error));
     } else {
       grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
       w->current = current;
@@ -191,8 +191,8 @@
       gpr_log(GPR_DEBUG, "NOTIFY: %p %s: %p", tracker, tracker->name,
               w->notify);
     }
-    grpc_exec_ctx_sched(exec_ctx, w->notify,
-                        GRPC_ERROR_REF(tracker->current_error), NULL);
+    grpc_closure_sched(exec_ctx, w->notify,
+                       GRPC_ERROR_REF(tracker->current_error));
     gpr_free(w);
   }
 }
diff --git a/src/core/lib/transport/mdstr_hash_table.c b/src/core/lib/transport/mdstr_hash_table.c
index 3d01e56..2791bf6 100644
--- a/src/core/lib/transport/mdstr_hash_table.c
+++ b/src/core/lib/transport/mdstr_hash_table.c
@@ -94,13 +94,14 @@
   return table;
 }
 
-void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) {
+void grpc_mdstr_hash_table_unref(grpc_exec_ctx* exec_ctx,
+                                 grpc_mdstr_hash_table* table) {
   if (table != NULL && gpr_unref(&table->refs)) {
     for (size_t i = 0; i < table->size; ++i) {
       grpc_mdstr_hash_table_entry* entry = &table->entries[i];
       if (entry->key != NULL) {
-        GRPC_MDSTR_UNREF(entry->key);
-        entry->vtable->destroy_value(entry->value);
+        GRPC_MDSTR_UNREF(exec_ctx, entry->key);
+        entry->vtable->destroy_value(exec_ctx, entry->value);
       }
     }
     gpr_free(table->entries);
diff --git a/src/core/lib/transport/mdstr_hash_table.h b/src/core/lib/transport/mdstr_hash_table.h
index 8982ec3..57f497e 100644
--- a/src/core/lib/transport/mdstr_hash_table.h
+++ b/src/core/lib/transport/mdstr_hash_table.h
@@ -49,7 +49,7 @@
 typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table;
 
 typedef struct grpc_mdstr_hash_table_vtable {
-  void (*destroy_value)(void* value);
+  void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value);
   void* (*copy_value)(void* value);
 } grpc_mdstr_hash_table_vtable;
 
@@ -66,7 +66,8 @@
     size_t num_entries, grpc_mdstr_hash_table_entry* entries);
 
 grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table);
-void grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table);
+void grpc_mdstr_hash_table_unref(grpc_exec_ctx* exec_ctx,
+                                 grpc_mdstr_hash_table* table);
 
 /** Returns the value from \a table associated with \a key.
     Returns NULL if \a key is not found. */
diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c
index fac19b9..54c39df 100644
--- a/src/core/lib/transport/metadata.c
+++ b/src/core/lib/transport/metadata.c
@@ -47,6 +47,7 @@
 
 #include "src/core/lib/iomgr/iomgr_internal.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/murmur_hash.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/static_metadata.h"
@@ -153,7 +154,7 @@
 static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
 static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
 
-static void gc_mdtab(mdtab_shard *shard);
+static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard);
 
 void grpc_test_only_set_metadata_hash_seed(uint32_t seed) {
   g_hash_seed = seed;
@@ -227,12 +228,12 @@
   }
 }
 
-void grpc_mdctx_global_shutdown(void) {
+void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx) {
   size_t i;
   for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
     mdtab_shard *shard = &g_mdtab_shard[i];
     gpr_mu_destroy(&shard->mu);
-    gc_mdtab(shard);
+    gc_mdtab(exec_ctx, shard);
     /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
     if (shard->count != 0) {
       gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked",
@@ -316,12 +317,13 @@
   GPR_TIMER_END("grow_strtab", 0);
 }
 
-static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
+static void internal_destroy_string(grpc_exec_ctx *exec_ctx,
+                                    strtab_shard *shard, internal_string *is) {
   internal_string **prev_next;
   internal_string *cur;
   GPR_TIMER_BEGIN("internal_destroy_string", 0);
   if (is->has_base64_and_huffman_encoded) {
-    grpc_slice_unref(is->base64_and_huffman);
+    grpc_slice_unref_internal(exec_ctx, is->base64_and_huffman);
   }
   for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
                                           shard->capacity)],
@@ -340,20 +342,20 @@
   GRPC_MDSTR_REF((grpc_mdstr *)(is));
 }
 
-static void slice_unref(void *p) {
+static void slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
   internal_string *is =
       (internal_string *)((char *)p - offsetof(internal_string, refcount));
-  GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
+  GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)(is));
 }
 
 grpc_mdstr *grpc_mdstr_from_string(const char *str) {
   return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
 }
 
-grpc_mdstr *grpc_mdstr_from_slice(grpc_slice slice) {
+grpc_mdstr *grpc_mdstr_from_slice(grpc_exec_ctx *exec_ctx, grpc_slice slice) {
   grpc_mdstr *result = grpc_mdstr_from_buffer(GRPC_SLICE_START_PTR(slice),
                                               GRPC_SLICE_LENGTH(slice));
-  grpc_slice_unref(slice);
+  grpc_slice_unref_internal(exec_ctx, slice);
   return result;
 }
 
@@ -444,7 +446,7 @@
   return (grpc_mdstr *)s;
 }
 
-static void gc_mdtab(mdtab_shard *shard) {
+static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
   size_t i;
   internal_metadata **prev_next;
   internal_metadata *md, *next;
@@ -457,8 +459,8 @@
       void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
       next = md->bucket_next;
       if (gpr_atm_acq_load(&md->refcnt) == 0) {
-        GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
-        GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
+        GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)md->key);
+        GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)md->value);
         if (md->user_data) {
           ((destroy_user_data_func)gpr_atm_no_barrier_load(
               &md->destroy_user_data))(user_data);
@@ -506,16 +508,17 @@
   GPR_TIMER_END("grow_mdtab", 0);
 }
 
-static void rehash_mdtab(mdtab_shard *shard) {
+static void rehash_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
   if (gpr_atm_no_barrier_load(&shard->free_estimate) >
       (gpr_atm)(shard->capacity / 4)) {
-    gc_mdtab(shard);
+    gc_mdtab(exec_ctx, shard);
   } else {
     grow_mdtab(shard);
   }
 }
 
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_exec_ctx *exec_ctx,
+                                               grpc_mdstr *mkey,
                                                grpc_mdstr *mvalue) {
   internal_string *key = (internal_string *)mkey;
   internal_string *value = (internal_string *)mvalue;
@@ -547,8 +550,8 @@
   for (md = shard->elems[idx]; md; md = md->bucket_next) {
     if (md->key == key && md->value == value) {
       REF_MD_LOCKED(shard, md);
-      GRPC_MDSTR_UNREF((grpc_mdstr *)key);
-      GRPC_MDSTR_UNREF((grpc_mdstr *)value);
+      GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)key);
+      GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)value);
       gpr_mu_unlock(&shard->mu);
       GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
       return (grpc_mdelem *)md;
@@ -574,7 +577,7 @@
   shard->count++;
 
   if (shard->count > shard->capacity * 2) {
-    rehash_mdtab(shard);
+    rehash_mdtab(exec_ctx, shard);
   }
 
   gpr_mu_unlock(&shard->mu);
@@ -584,21 +587,26 @@
   return (grpc_mdelem *)md;
 }
 
-grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
-  return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
-                                           grpc_mdstr_from_string(value));
+grpc_mdelem *grpc_mdelem_from_strings(grpc_exec_ctx *exec_ctx, const char *key,
+                                      const char *value) {
+  return grpc_mdelem_from_metadata_strings(
+      exec_ctx, grpc_mdstr_from_string(key), grpc_mdstr_from_string(value));
 }
 
-grpc_mdelem *grpc_mdelem_from_slices(grpc_slice key, grpc_slice value) {
-  return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
-                                           grpc_mdstr_from_slice(value));
+grpc_mdelem *grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
+                                     grpc_slice value) {
+  return grpc_mdelem_from_metadata_strings(
+      exec_ctx, grpc_mdstr_from_slice(exec_ctx, key),
+      grpc_mdstr_from_slice(exec_ctx, value));
 }
 
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_exec_ctx *exec_ctx,
+                                                const char *key,
                                                 const uint8_t *value,
                                                 size_t value_length) {
   return grpc_mdelem_from_metadata_strings(
-      grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
+      exec_ctx, grpc_mdstr_from_string(key),
+      grpc_mdstr_from_buffer(value, value_length));
 }
 
 static size_t get_base64_encoded_size(size_t raw_length) {
@@ -654,7 +662,7 @@
   return gmd;
 }
 
-void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
+void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *gmd DEBUG_ARGS) {
   internal_metadata *md = (internal_metadata *)gmd;
   if (!md) return;
   if (is_mdelem_static(gmd)) return;
@@ -696,7 +704,7 @@
   return gs;
 }
 
-void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
+void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *gs DEBUG_ARGS) {
   internal_string *s = (internal_string *)gs;
   if (is_mdstr_static(gs)) return;
 #ifdef GRPC_METADATA_REFCOUNT_DEBUG
@@ -709,7 +717,7 @@
         &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
     gpr_mu_lock(&shard->mu);
     GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt));
-    internal_destroy_string(shard, s);
+    internal_destroy_string(exec_ctx, shard, s);
     gpr_mu_unlock(&shard->mu);
   }
 }
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index a4955a1..991eee9 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -37,6 +37,8 @@
 #include <grpc/slice.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -96,7 +98,7 @@
    clients may have handy */
 grpc_mdstr *grpc_mdstr_from_string(const char *str);
 /* Unrefs the slice. */
-grpc_mdstr *grpc_mdstr_from_slice(grpc_slice slice);
+grpc_mdstr *grpc_mdstr_from_slice(grpc_exec_ctx *exec_ctx, grpc_slice slice);
 grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *str, size_t length);
 
 /* Returns a borrowed slice from the mdstr with its contents base64 encoded
@@ -105,12 +107,16 @@
 
 /* Constructors for grpc_mdelem instances; take a variety of data types that
    clients may have handy */
-grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *key,
+grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_exec_ctx *exec_ctx,
+                                               grpc_mdstr *key,
                                                grpc_mdstr *value);
-grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value);
+grpc_mdelem *grpc_mdelem_from_strings(grpc_exec_ctx *exec_ctx, const char *key,
+                                      const char *value);
 /* Unrefs the slices. */
-grpc_mdelem *grpc_mdelem_from_slices(grpc_slice key, grpc_slice value);
-grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
+grpc_mdelem *grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
+                                     grpc_slice value);
+grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_exec_ctx *exec_ctx,
+                                                const char *key,
                                                 const uint8_t *value,
                                                 size_t value_length);
 
@@ -127,22 +133,26 @@
 //#define GRPC_METADATA_REFCOUNT_DEBUG
 #ifdef GRPC_METADATA_REFCOUNT_DEBUG
 #define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s), __FILE__, __LINE__)
-#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s), __FILE__, __LINE__)
+#define GRPC_MDSTR_UNREF(exec_ctx, s) \
+  grpc_mdstr_unref((exec_ctx), (s), __FILE__, __LINE__)
 #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s), __FILE__, __LINE__)
-#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s), __FILE__, __LINE__)
+#define GRPC_MDELEM_UNREF(exec_ctx, s) \
+  grpc_mdelem_unref((exec_ctx), (s), __FILE__, __LINE__)
 grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s, const char *file, int line);
-void grpc_mdstr_unref(grpc_mdstr *s, const char *file, int line);
+void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *s, const char *file,
+                      int line);
 grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md, const char *file, int line);
-void grpc_mdelem_unref(grpc_mdelem *md, const char *file, int line);
+void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *md,
+                       const char *file, int line);
 #else
 #define GRPC_MDSTR_REF(s) grpc_mdstr_ref((s))
-#define GRPC_MDSTR_UNREF(s) grpc_mdstr_unref((s))
+#define GRPC_MDSTR_UNREF(exec_ctx, s) grpc_mdstr_unref((exec_ctx), (s))
 #define GRPC_MDELEM_REF(s) grpc_mdelem_ref((s))
-#define GRPC_MDELEM_UNREF(s) grpc_mdelem_unref((s))
+#define GRPC_MDELEM_UNREF(exec_ctx, s) grpc_mdelem_unref((exec_ctx), (s))
 grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *s);
-void grpc_mdstr_unref(grpc_mdstr *s);
+void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *s);
 grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *md);
-void grpc_mdelem_unref(grpc_mdelem *md);
+void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *md);
 #endif
 
 /* Recover a char* from a grpc_mdstr. The returned string is null terminated.
@@ -162,7 +172,7 @@
 #define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
 
 void grpc_mdctx_global_init(void);
-void grpc_mdctx_global_shutdown(void);
+void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx);
 
 /* Implementation provided by chttp2_transport */
 extern grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(
diff --git a/src/core/lib/transport/metadata_batch.c b/src/core/lib/transport/metadata_batch.c
index 84b5a74..b62ecc3 100644
--- a/src/core/lib/transport/metadata_batch.c
+++ b/src/core/lib/transport/metadata_batch.c
@@ -72,10 +72,11 @@
   batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
 }
 
-void grpc_metadata_batch_destroy(grpc_metadata_batch *batch) {
+void grpc_metadata_batch_destroy(grpc_exec_ctx *exec_ctx,
+                                 grpc_metadata_batch *batch) {
   grpc_linked_mdelem *l;
   for (l = batch->list.head; l; l = l->next) {
-    GRPC_MDELEM_UNREF(l->md);
+    GRPC_MDELEM_UNREF(exec_ctx, l->md);
   }
 }
 
@@ -140,8 +141,10 @@
   memset(src, 0, sizeof(grpc_metadata_batch));
 }
 
-void grpc_metadata_batch_filter(grpc_metadata_batch *batch,
-                                grpc_mdelem *(*filter)(void *user_data,
+void grpc_metadata_batch_filter(grpc_exec_ctx *exec_ctx,
+                                grpc_metadata_batch *batch,
+                                grpc_mdelem *(*filter)(grpc_exec_ctx *exec_ctx,
+                                                       void *user_data,
                                                        grpc_mdelem *elem),
                                 void *user_data) {
   grpc_linked_mdelem *l;
@@ -152,7 +155,7 @@
   assert_valid_list(&batch->list);
   for (l = batch->list.head; l; l = next) {
     grpc_mdelem *orig = l->md;
-    grpc_mdelem *filt = filter(user_data, orig);
+    grpc_mdelem *filt = filter(exec_ctx, user_data, orig);
     next = l->next;
     if (filt == NULL) {
       if (l->prev) {
@@ -168,9 +171,9 @@
         batch->list.tail = l->prev;
       }
       assert_valid_list(&batch->list);
-      GRPC_MDELEM_UNREF(l->md);
+      GRPC_MDELEM_UNREF(exec_ctx, l->md);
     } else if (filt != orig) {
-      GRPC_MDELEM_UNREF(orig);
+      GRPC_MDELEM_UNREF(exec_ctx, orig);
       l->md = filt;
     }
   }
@@ -179,13 +182,15 @@
   GPR_TIMER_END("grpc_metadata_batch_filter", 0);
 }
 
-static grpc_mdelem *no_metadata_for_you(void *user_data, grpc_mdelem *elem) {
+static grpc_mdelem *no_metadata_for_you(grpc_exec_ctx *exec_ctx,
+                                        void *user_data, grpc_mdelem *elem) {
   return NULL;
 }
 
-void grpc_metadata_batch_clear(grpc_metadata_batch *batch) {
+void grpc_metadata_batch_clear(grpc_exec_ctx *exec_ctx,
+                               grpc_metadata_batch *batch) {
   batch->deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-  grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL);
+  grpc_metadata_batch_filter(exec_ctx, batch, no_metadata_for_you, NULL);
 }
 
 bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 7a9ccb4..c0bd517 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -68,8 +68,10 @@
 } grpc_metadata_batch;
 
 void grpc_metadata_batch_init(grpc_metadata_batch *batch);
-void grpc_metadata_batch_destroy(grpc_metadata_batch *batch);
-void grpc_metadata_batch_clear(grpc_metadata_batch *batch);
+void grpc_metadata_batch_destroy(grpc_exec_ctx *exec_ctx,
+                                 grpc_metadata_batch *batch);
+void grpc_metadata_batch_clear(grpc_exec_ctx *exec_ctx,
+                               grpc_metadata_batch *batch);
 bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
 
 /* Returns the transport size of the batch. */
@@ -118,8 +120,10 @@
     The return value from \a filter will be substituted for the
     grpc_mdelem passed to \a filter. If \a filter returns NULL,
     the element will be moved to the garbage list. */
-void grpc_metadata_batch_filter(grpc_metadata_batch *batch,
-                                grpc_mdelem *(*filter)(void *user_data,
+void grpc_metadata_batch_filter(grpc_exec_ctx *exec_ctx,
+                                grpc_metadata_batch *batch,
+                                grpc_mdelem *(*filter)(grpc_exec_ctx *exec_ctx,
+                                                       void *user_data,
                                                        grpc_mdelem *elem),
                                 void *user_data);
 
diff --git a/src/core/lib/transport/method_config.c b/src/core/lib/transport/method_config.c
new file mode 100644
index 0000000..25fb54b
--- /dev/null
+++ b/src/core/lib/transport/method_config.c
@@ -0,0 +1,347 @@
+//
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#include "src/core/lib/transport/method_config.h"
+
+#include <string.h>
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/transport/mdstr_hash_table.h"
+#include "src/core/lib/transport/metadata.h"
+
+//
+// grpc_method_config
+//
+
+// bool vtable
+
+static void* bool_copy(void* valuep) {
+  bool value = *(bool*)valuep;
+  bool* new_value = gpr_malloc(sizeof(bool));
+  *new_value = value;
+  return new_value;
+}
+
+static int bool_cmp(void* v1, void* v2) {
+  bool b1 = *(bool*)v1;
+  bool b2 = *(bool*)v2;
+  if (!b1 && b2) return -1;
+  if (b1 && !b2) return 1;
+  return 0;
+}
+
+static void free_mem(grpc_exec_ctx* exec_ctx, void* p) { gpr_free(p); }
+
+static grpc_mdstr_hash_table_vtable bool_vtable = {free_mem, bool_copy,
+                                                   bool_cmp};
+
+// timespec vtable
+
+static void* timespec_copy(void* valuep) {
+  gpr_timespec value = *(gpr_timespec*)valuep;
+  gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec));
+  *new_value = value;
+  return new_value;
+}
+
+static int timespec_cmp(void* v1, void* v2) {
+  return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2);
+}
+
+static grpc_mdstr_hash_table_vtable timespec_vtable = {free_mem, timespec_copy,
+                                                       timespec_cmp};
+
+// int32 vtable
+
+static void* int32_copy(void* valuep) {
+  int32_t value = *(int32_t*)valuep;
+  int32_t* new_value = gpr_malloc(sizeof(int32_t));
+  *new_value = value;
+  return new_value;
+}
+
+static int int32_cmp(void* v1, void* v2) {
+  int32_t i1 = *(int32_t*)v1;
+  int32_t i2 = *(int32_t*)v2;
+  if (i1 < i2) return -1;
+  if (i1 > i2) return 1;
+  return 0;
+}
+
+static grpc_mdstr_hash_table_vtable int32_vtable = {free_mem, int32_copy,
+                                                    int32_cmp};
+
+// Hash table keys.
+#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready"  // bool
+#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout"                // gpr_timespec
+#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \
+  "grpc.max_request_message_bytes"  // int32
+#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \
+  "grpc.max_response_message_bytes"  // int32
+
+struct grpc_method_config {
+  grpc_mdstr_hash_table* table;
+  grpc_mdstr* wait_for_ready_key;
+  grpc_mdstr* timeout_key;
+  grpc_mdstr* max_request_message_bytes_key;
+  grpc_mdstr* max_response_message_bytes_key;
+};
+
+grpc_method_config* grpc_method_config_create(
+    bool* wait_for_ready, gpr_timespec* timeout,
+    int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) {
+  grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config));
+  memset(method_config, 0, sizeof(grpc_method_config));
+  method_config->wait_for_ready_key =
+      grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY);
+  method_config->timeout_key =
+      grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT);
+  method_config->max_request_message_bytes_key =
+      grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES);
+  method_config->max_response_message_bytes_key =
+      grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES);
+  grpc_mdstr_hash_table_entry entries[4];
+  size_t num_entries = 0;
+  if (wait_for_ready != NULL) {
+    entries[num_entries].key = method_config->wait_for_ready_key;
+    entries[num_entries].value = wait_for_ready;
+    entries[num_entries].vtable = &bool_vtable;
+    ++num_entries;
+  }
+  if (timeout != NULL) {
+    entries[num_entries].key = method_config->timeout_key;
+    entries[num_entries].value = timeout;
+    entries[num_entries].vtable = &timespec_vtable;
+    ++num_entries;
+  }
+  if (max_request_message_bytes != NULL) {
+    entries[num_entries].key = method_config->max_request_message_bytes_key;
+    entries[num_entries].value = max_request_message_bytes;
+    entries[num_entries].vtable = &int32_vtable;
+    ++num_entries;
+  }
+  if (max_response_message_bytes != NULL) {
+    entries[num_entries].key = method_config->max_response_message_bytes_key;
+    entries[num_entries].value = max_response_message_bytes;
+    entries[num_entries].vtable = &int32_vtable;
+    ++num_entries;
+  }
+  method_config->table = grpc_mdstr_hash_table_create(num_entries, entries);
+  return method_config;
+}
+
+grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) {
+  grpc_mdstr_hash_table_ref(method_config->table);
+  return method_config;
+}
+
+void grpc_method_config_unref(grpc_exec_ctx* exec_ctx,
+                              grpc_method_config* method_config) {
+  if (grpc_mdstr_hash_table_unref(exec_ctx, method_config->table)) {
+    GRPC_MDSTR_UNREF(exec_ctx, method_config->wait_for_ready_key);
+    GRPC_MDSTR_UNREF(exec_ctx, method_config->timeout_key);
+    GRPC_MDSTR_UNREF(exec_ctx, method_config->max_request_message_bytes_key);
+    GRPC_MDSTR_UNREF(exec_ctx, method_config->max_response_message_bytes_key);
+    gpr_free(method_config);
+  }
+}
+
+int grpc_method_config_cmp(const grpc_method_config* method_config1,
+                           const grpc_method_config* method_config2) {
+  return grpc_mdstr_hash_table_cmp(method_config1->table,
+                                   method_config2->table);
+}
+
+const bool* grpc_method_config_get_wait_for_ready(
+    const grpc_method_config* method_config) {
+  return grpc_mdstr_hash_table_get(method_config->table,
+                                   method_config->wait_for_ready_key);
+}
+
+const gpr_timespec* grpc_method_config_get_timeout(
+    const grpc_method_config* method_config) {
+  return grpc_mdstr_hash_table_get(method_config->table,
+                                   method_config->timeout_key);
+}
+
+const int32_t* grpc_method_config_get_max_request_message_bytes(
+    const grpc_method_config* method_config) {
+  return grpc_mdstr_hash_table_get(
+      method_config->table, method_config->max_request_message_bytes_key);
+}
+
+const int32_t* grpc_method_config_get_max_response_message_bytes(
+    const grpc_method_config* method_config) {
+  return grpc_mdstr_hash_table_get(
+      method_config->table, method_config->max_response_message_bytes_key);
+}
+
+//
+// grpc_method_config_table
+//
+
+static void method_config_unref(grpc_exec_ctx* exec_ctx, void* valuep) {
+  grpc_method_config_unref(exec_ctx, valuep);
+}
+
+static void* method_config_ref(void* valuep) {
+  return grpc_method_config_ref(valuep);
+}
+
+static int method_config_cmp(void* valuep1, void* valuep2) {
+  return grpc_method_config_cmp(valuep1, valuep2);
+}
+
+static const grpc_mdstr_hash_table_vtable method_config_table_vtable = {
+    method_config_unref, method_config_ref, method_config_cmp};
+
+grpc_method_config_table* grpc_method_config_table_create(
+    size_t num_entries, grpc_method_config_table_entry* entries) {
+  grpc_mdstr_hash_table_entry* hash_table_entries =
+      gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries);
+  for (size_t i = 0; i < num_entries; ++i) {
+    hash_table_entries[i].key = entries[i].method_name;
+    hash_table_entries[i].value = entries[i].method_config;
+    hash_table_entries[i].vtable = &method_config_table_vtable;
+  }
+  grpc_method_config_table* method_config_table =
+      grpc_mdstr_hash_table_create(num_entries, hash_table_entries);
+  gpr_free(hash_table_entries);
+  return method_config_table;
+}
+
+grpc_method_config_table* grpc_method_config_table_ref(
+    grpc_method_config_table* table) {
+  return grpc_mdstr_hash_table_ref(table);
+}
+
+void grpc_method_config_table_unref(grpc_exec_ctx* exec_ctx,
+                                    grpc_method_config_table* table) {
+  grpc_mdstr_hash_table_unref(exec_ctx, table);
+}
+
+int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
+                                 const grpc_method_config_table* table2) {
+  return grpc_mdstr_hash_table_cmp(table1, table2);
+}
+
+void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
+                                   const grpc_mdstr_hash_table* table,
+                                   const grpc_mdstr* path) {
+  void* value = grpc_mdstr_hash_table_get(table, path);
+  // If we didn't find a match for the path, try looking for a wildcard
+  // entry (i.e., change "/service/method" to "/service/*").
+  if (value == NULL) {
+    const char* path_str = grpc_mdstr_as_c_string(path);
+    const char* sep = strrchr(path_str, '/') + 1;
+    const size_t len = (size_t)(sep - path_str);
+    char* buf = gpr_malloc(len + 2);  // '*' and NUL
+    memcpy(buf, path_str, len);
+    buf[len] = '*';
+    buf[len + 1] = '\0';
+    grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
+    gpr_free(buf);
+    value = grpc_mdstr_hash_table_get(table, wildcard_path);
+    GRPC_MDSTR_UNREF(exec_ctx, wildcard_path);
+  }
+  return value;
+}
+
+static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); }
+
+static void destroy_arg(grpc_exec_ctx* exec_ctx, void* p) {
+  grpc_method_config_table_unref(exec_ctx, p);
+}
+
+static int cmp_arg(void* p1, void* p2) {
+  return grpc_method_config_table_cmp(p1, p2);
+}
+
+static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg};
+
+grpc_arg grpc_method_config_table_create_channel_arg(
+    grpc_method_config_table* table) {
+  grpc_arg arg;
+  arg.type = GRPC_ARG_POINTER;
+  arg.key = GRPC_ARG_SERVICE_CONFIG;
+  arg.value.pointer.p = table;
+  arg.value.pointer.vtable = &arg_vtable;
+  return arg;
+}
+
+// State used by convert_entry() below.
+typedef struct conversion_state {
+  void* (*convert_value)(const grpc_method_config* method_config);
+  const grpc_mdstr_hash_table_vtable* vtable;
+  size_t num_entries;
+  grpc_mdstr_hash_table_entry* entries;
+} conversion_state;
+
+// A function to be passed to grpc_mdstr_hash_table_iterate() to create
+// a copy of the entries.
+static void convert_entry(const grpc_mdstr_hash_table_entry* entry,
+                          void* user_data) {
+  conversion_state* state = user_data;
+  state->entries[state->num_entries].key = GRPC_MDSTR_REF(entry->key);
+  state->entries[state->num_entries].value = state->convert_value(entry->value);
+  state->entries[state->num_entries].vtable = state->vtable;
+  ++state->num_entries;
+}
+
+grpc_mdstr_hash_table* grpc_method_config_table_convert(
+    grpc_exec_ctx* exec_ctx, const grpc_method_config_table* table,
+    void* (*convert_value)(const grpc_method_config* method_config),
+    const grpc_mdstr_hash_table_vtable* vtable) {
+  // Create an array of the entries in the table with converted values.
+  conversion_state state;
+  state.convert_value = convert_value;
+  state.vtable = vtable;
+  state.num_entries = 0;
+  state.entries = gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) *
+                             grpc_mdstr_hash_table_num_entries(table));
+  grpc_mdstr_hash_table_iterate(table, convert_entry, &state);
+  // Create a new table based on the array we just constructed.
+  grpc_mdstr_hash_table* new_table =
+      grpc_mdstr_hash_table_create(state.num_entries, state.entries);
+  // Clean up the array.
+  for (size_t i = 0; i < state.num_entries; ++i) {
+    GRPC_MDSTR_UNREF(exec_ctx, state.entries[i].key);
+    vtable->destroy_value(exec_ctx, state.entries[i].value);
+  }
+  gpr_free(state.entries);
+  // Return the new table.
+  return new_table;
+}
diff --git a/src/core/lib/transport/method_config.h b/src/core/lib/transport/method_config.h
new file mode 100644
index 0000000..d17a493
--- /dev/null
+++ b/src/core/lib/transport/method_config.h
@@ -0,0 +1,139 @@
+//
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
+#define GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H
+
+#include <stdbool.h>
+
+#include <grpc/impl/codegen/gpr_types.h>
+#include <grpc/impl/codegen/grpc_types.h>
+
+#include "src/core/lib/transport/mdstr_hash_table.h"
+#include "src/core/lib/transport/metadata.h"
+
+/// Per-method configuration.
+typedef struct grpc_method_config grpc_method_config;
+
+/// Creates a grpc_method_config with the specified parameters.
+/// Any parameter may be NULL to indicate that the value is unset.
+///
+/// \a wait_for_ready indicates whether the client should wait until the
+/// request deadline for the channel to become ready, even if there is a
+/// temporary failure before the deadline while attempting to connect.
+///
+/// \a timeout indicates the timeout for calls.
+///
+/// \a max_request_message_bytes and \a max_response_message_bytes
+/// indicate the maximum sizes of the request (checked when sending) and
+/// response (checked when receiving) messages.
+grpc_method_config* grpc_method_config_create(
+    bool* wait_for_ready, gpr_timespec* timeout,
+    int32_t* max_request_message_bytes, int32_t* max_response_message_bytes);
+
+grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config);
+void grpc_method_config_unref(grpc_exec_ctx* exec_ctx,
+                              grpc_method_config* method_config);
+
+/// Compares two grpc_method_configs.
+/// The sort order is stable but undefined.
+int grpc_method_config_cmp(const grpc_method_config* method_config1,
+                           const grpc_method_config* method_config2);
+
+/// These methods return NULL if the requested field is unset.
+/// The caller does NOT take ownership of the result.
+const bool* grpc_method_config_get_wait_for_ready(
+    const grpc_method_config* method_config);
+const gpr_timespec* grpc_method_config_get_timeout(
+    const grpc_method_config* method_config);
+const int32_t* grpc_method_config_get_max_request_message_bytes(
+    const grpc_method_config* method_config);
+const int32_t* grpc_method_config_get_max_response_message_bytes(
+    const grpc_method_config* method_config);
+
+/// A table of method configs.
+typedef grpc_mdstr_hash_table grpc_method_config_table;
+
+typedef struct grpc_method_config_table_entry {
+  /// The name is of one of the following forms:
+  ///   service/method -- specifies exact service and method name
+  ///   service/*      -- matches all methods for the specified service
+  grpc_mdstr* method_name;
+  grpc_method_config* method_config;
+} grpc_method_config_table_entry;
+
+/// Takes new references to all keys and values in \a entries.
+grpc_method_config_table* grpc_method_config_table_create(
+    size_t num_entries, grpc_method_config_table_entry* entries);
+
+grpc_method_config_table* grpc_method_config_table_ref(
+    grpc_method_config_table* table);
+void grpc_method_config_table_unref(grpc_exec_ctx* exec_ctx,
+                                    grpc_method_config_table* table);
+
+/// Compares two grpc_method_config_tables.
+/// The sort order is stable but undefined.
+int grpc_method_config_table_cmp(const grpc_method_config_table* table1,
+                                 const grpc_method_config_table* table2);
+
+/// Gets the method config for the specified \a path, which should be of
+/// the form "/service/method".
+/// Returns NULL if the method has no config.
+/// Caller does NOT own a reference to the result.
+///
+/// Note: This returns a void* instead of a grpc_method_config* so that
+/// it can also be used for tables constructed via
+/// grpc_method_config_table_convert().
+void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
+                                   const grpc_mdstr_hash_table* table,
+                                   const grpc_mdstr* path);
+
+/// Returns a channel arg containing \a table.
+grpc_arg grpc_method_config_table_create_channel_arg(
+    grpc_method_config_table* table);
+
+/// Generates a new table from \a table whose values are converted to a
+/// new form via the \a convert_value function.  The new table will use
+/// \a vtable for its values.
+///
+/// This is generally used to convert the table's value type from
+/// grpc_method_config to a simple struct containing only the parameters
+/// relevant to a particular filter, thus avoiding the need for a hash
+/// table lookup on the fast path.  In that scenario, \a convert_value
+/// will return a new instance of the struct containing the values from
+/// the grpc_method_config, and \a vtable provides the methods for
+/// operating on the struct type.
+grpc_mdstr_hash_table* grpc_method_config_table_convert(
+    grpc_exec_ctx* exec_ctx, const grpc_method_config_table* table,
+    void* (*convert_value)(const grpc_method_config* method_config),
+    const grpc_mdstr_hash_table_vtable* vtable);
+
+#endif /* GRPC_CORE_LIB_TRANSPORT_METHOD_CONFIG_H */
diff --git a/src/core/lib/transport/pid_controller.h b/src/core/lib/transport/pid_controller.h
index 059b5b0..83c82d6 100644
--- a/src/core/lib/transport/pid_controller.h
+++ b/src/core/lib/transport/pid_controller.h
@@ -61,4 +61,4 @@
 double grpc_pid_controller_update(grpc_pid_controller *pid_controller,
                                   double error, double dt);
 
-#endif
+#endif /* GRPC_CORE_LIB_TRANSPORT_PID_CONTROLLER_H */
diff --git a/src/core/lib/transport/service_config.c b/src/core/lib/transport/service_config.c
index 2e2b59e..552d3ec 100644
--- a/src/core/lib/transport/service_config.c
+++ b/src/core/lib/transport/service_config.c
@@ -146,7 +146,8 @@
 // each name found, incrementing \a idx for each entry added.
 // Returns false on error.
 static bool parse_json_method_config(
-    grpc_json* json, void* (*create_value)(const grpc_json* method_config_json),
+    grpc_exec_ctx* exec_ctx, grpc_json* json,
+    void* (*create_value)(const grpc_json* method_config_json),
     const grpc_mdstr_hash_table_vtable* vtable,
     grpc_mdstr_hash_table_entry* entries, size_t* idx) {
   // Construct value.
@@ -176,13 +177,13 @@
   }
   success = true;
 done:
-  vtable->destroy_value(method_config);
+  vtable->destroy_value(exec_ctx, method_config);
   gpr_strvec_destroy(&paths);
   return success;
 }
 
 grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
-    const grpc_service_config* service_config,
+    grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
     void* (*create_value)(const grpc_json* method_config_json),
     const grpc_mdstr_hash_table_vtable* vtable) {
   const grpc_json* json = service_config->json_tree;
@@ -205,8 +206,8 @@
       size_t idx = 0;
       for (grpc_json* method = field->child; method != NULL;
            method = method->next) {
-        if (!parse_json_method_config(method, create_value, vtable, entries,
-                                      &idx)) {
+        if (!parse_json_method_config(exec_ctx, method, create_value, vtable,
+                                      entries, &idx)) {
           return NULL;
         }
       }
@@ -219,15 +220,16 @@
     method_config_table = grpc_mdstr_hash_table_create(num_entries, entries);
     // Clean up.
     for (size_t i = 0; i < num_entries; ++i) {
-      GRPC_MDSTR_UNREF(entries[i].key);
-      vtable->destroy_value(entries[i].value);
+      GRPC_MDSTR_UNREF(exec_ctx, entries[i].key);
+      vtable->destroy_value(exec_ctx, entries[i].value);
     }
     gpr_free(entries);
   }
   return method_config_table;
 }
 
-void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
+void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
+                                   const grpc_mdstr_hash_table* table,
                                    const grpc_mdstr* path) {
   void* value = grpc_mdstr_hash_table_get(table, path);
   // If we didn't find a match for the path, try looking for a wildcard
@@ -243,7 +245,7 @@
     grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf);
     gpr_free(buf);
     value = grpc_mdstr_hash_table_get(table, wildcard_path);
-    GRPC_MDSTR_UNREF(wildcard_path);
+    GRPC_MDSTR_UNREF(exec_ctx, wildcard_path);
   }
   return value;
 }
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index 2ffe475..f089717 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -54,7 +54,7 @@
 /// \a vtable provides methods used to manage the values.
 /// Returns NULL on error.
 grpc_mdstr_hash_table* grpc_service_config_create_method_config_table(
-    const grpc_service_config* service_config,
+    grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
     void* (*create_value)(const grpc_json* method_config_json),
     const grpc_mdstr_hash_table_vtable* vtable);
 
@@ -64,7 +64,8 @@
 /// the form "/service/method".
 /// Returns NULL if the method has no config.
 /// Caller does NOT own a reference to the result.
-void* grpc_method_config_table_get(const grpc_mdstr_hash_table* table,
+void* grpc_method_config_table_get(grpc_exec_ctx* exec_ctx,
+                                   const grpc_mdstr_hash_table* table,
                                    const grpc_mdstr* path);
 
 #endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index b448126..055edbb 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -40,6 +40,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/transport_impl.h"
@@ -68,7 +69,7 @@
                        grpc_stream_refcount *refcount) {
 #endif
   if (gpr_unref(&refcount->refs)) {
-    grpc_exec_ctx_sched(exec_ctx, &refcount->destroy, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, &refcount->destroy, GRPC_ERROR_NONE);
   }
 }
 
@@ -82,7 +83,7 @@
                           grpc_iomgr_cb_func cb, void *cb_arg) {
 #endif
   gpr_ref_init(&refcount->refs, initial_refs);
-  grpc_closure_init(&refcount->destroy, cb, cb_arg);
+  grpc_closure_init(&refcount->destroy, cb, cb_arg, grpc_schedule_on_exec_ctx);
 }
 
 static void move64(uint64_t *from, uint64_t *to) {
@@ -168,11 +169,10 @@
 void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
                                                   grpc_transport_stream_op *op,
                                                   grpc_error *error) {
-  grpc_exec_ctx_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_REF(error),
-                      NULL);
-  grpc_exec_ctx_sched(exec_ctx, op->recv_initial_metadata_ready,
-                      GRPC_ERROR_REF(error), NULL);
-  grpc_exec_ctx_sched(exec_ctx, op->on_complete, error, NULL);
+  grpc_closure_sched(exec_ctx, op->recv_message_ready, GRPC_ERROR_REF(error));
+  grpc_closure_sched(exec_ctx, op->recv_initial_metadata_ready,
+                     GRPC_ERROR_REF(error));
+  grpc_closure_sched(exec_ctx, op->on_complete, error);
 }
 
 typedef struct {
@@ -196,7 +196,8 @@
   cmd = gpr_malloc(sizeof(*cmd));
   cmd->error = error;
   cmd->then_call = op->on_complete;
-  grpc_closure_init(&cmd->closure, free_message, cmd);
+  grpc_closure_init(&cmd->closure, free_message, cmd,
+                    grpc_schedule_on_exec_ctx);
   op->on_complete = &cmd->closure;
   *which = error;
 }
@@ -212,12 +213,12 @@
 }
 
 void grpc_transport_stream_op_add_cancellation_with_message(
-    grpc_transport_stream_op *op, grpc_status_code status,
-    grpc_slice *optional_message) {
+    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op,
+    grpc_status_code status, grpc_slice *optional_message) {
   GPR_ASSERT(status != GRPC_STATUS_OK);
   if (op->cancel_error != GRPC_ERROR_NONE) {
     if (optional_message) {
-      grpc_slice_unref(*optional_message);
+      grpc_slice_unref_internal(exec_ctx, *optional_message);
     }
     return;
   }
@@ -227,7 +228,7 @@
     error = grpc_error_set_str(GRPC_ERROR_CREATE(msg),
                                GRPC_ERROR_STR_GRPC_MESSAGE, msg);
     gpr_free(msg);
-    grpc_slice_unref(*optional_message);
+    grpc_slice_unref_internal(exec_ctx, *optional_message);
   } else {
     error = GRPC_ERROR_CREATE("Call cancelled");
   }
@@ -235,14 +236,15 @@
   add_error(op, &op->cancel_error, error);
 }
 
-void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
+void grpc_transport_stream_op_add_close(grpc_exec_ctx *exec_ctx,
+                                        grpc_transport_stream_op *op,
                                         grpc_status_code status,
                                         grpc_slice *optional_message) {
   GPR_ASSERT(status != GRPC_STATUS_OK);
   if (op->cancel_error != GRPC_ERROR_NONE ||
       op->close_error != GRPC_ERROR_NONE) {
     if (optional_message) {
-      grpc_slice_unref(*optional_message);
+      grpc_slice_unref_internal(exec_ctx, *optional_message);
     }
     return;
   }
@@ -252,7 +254,7 @@
     error = grpc_error_set_str(GRPC_ERROR_CREATE(msg),
                                GRPC_ERROR_STR_GRPC_MESSAGE, msg);
     gpr_free(msg);
-    grpc_slice_unref(*optional_message);
+    grpc_slice_unref_internal(exec_ctx, *optional_message);
   } else {
     error = GRPC_ERROR_CREATE("Call force closed");
   }
@@ -269,14 +271,14 @@
 static void destroy_made_transport_op(grpc_exec_ctx *exec_ctx, void *arg,
                                       grpc_error *error) {
   made_transport_op *op = arg;
-  grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error),
-                      NULL);
+  grpc_closure_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error));
   gpr_free(op);
 }
 
 grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) {
   made_transport_op *op = gpr_malloc(sizeof(*op));
-  grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op);
+  grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op,
+                    grpc_schedule_on_exec_ctx);
   op->inner_on_complete = on_complete;
   memset(&op->op, 0, sizeof(op->op));
   op->op.on_consumed = &op->outer_on_complete;
@@ -292,8 +294,7 @@
 static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg,
                                              grpc_error *error) {
   made_transport_stream_op *op = arg;
-  grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error),
-                      NULL);
+  grpc_closure_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error));
   gpr_free(op);
 }
 
@@ -301,7 +302,7 @@
     grpc_closure *on_complete) {
   made_transport_stream_op *op = gpr_malloc(sizeof(*op));
   grpc_closure_init(&op->outer_on_complete, destroy_made_transport_stream_op,
-                    op);
+                    op, grpc_schedule_on_exec_ctx);
   op->inner_on_complete = on_complete;
   memset(&op->op, 0, sizeof(op->op));
   op->op.on_complete = &op->outer_on_complete;
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 96c2674..d128183 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -249,10 +249,11 @@
                                                grpc_status_code status);
 
 void grpc_transport_stream_op_add_cancellation_with_message(
-    grpc_transport_stream_op *op, grpc_status_code status,
-    grpc_slice *optional_message);
+    grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op,
+    grpc_status_code status, grpc_slice *optional_message);
 
-void grpc_transport_stream_op_add_close(grpc_transport_stream_op *op,
+void grpc_transport_stream_op_add_close(grpc_exec_ctx *exec_ctx,
+                                        grpc_transport_stream_op *op,
                                         grpc_status_code status,
                                         grpc_slice *optional_message);
 
diff --git a/src/core/lib/tsi/README.md b/src/core/lib/tsi/README.md
new file mode 100644
index 0000000..3ca3c1e
--- /dev/null
+++ b/src/core/lib/tsi/README.md
@@ -0,0 +1,2 @@
+# Transport Security Interface
+An abstraction library over crypto and auth modules (typically OpenSSL)
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index 0301b5b..1fdd106 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -38,8 +38,11 @@
 #include <grpc++/resource_quota.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/log.h>
+extern "C" {
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
+}
 namespace grpc {
 
 ChannelArguments::ChannelArguments() {
@@ -94,13 +97,15 @@
   }
   grpc_arg mutator_arg = grpc_socket_mutator_to_arg(mutator);
   bool replaced = false;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   for (auto it = args_.begin(); it != args_.end(); ++it) {
     if (it->type == mutator_arg.type &&
         grpc::string(it->key) == grpc::string(mutator_arg.key)) {
-      it->value.pointer.vtable->destroy(it->value.pointer.p);
+      it->value.pointer.vtable->destroy(&exec_ctx, it->value.pointer.p);
       it->value.pointer = mutator_arg.value.pointer;
     }
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   if (!replaced) {
     args_.push_back(mutator_arg);
   }
diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc
index ad2c0f2..c0dc9dd 100644
--- a/src/cpp/common/channel_filter.cc
+++ b/src/cpp/common/channel_filter.cc
@@ -40,11 +40,12 @@
 
 // MetadataBatch
 
-grpc_linked_mdelem *MetadataBatch::AddMetadata(const string &key,
+grpc_linked_mdelem *MetadataBatch::AddMetadata(grpc_exec_ctx *exec_ctx,
+                                               const string &key,
                                                const string &value) {
   grpc_linked_mdelem *storage = new grpc_linked_mdelem;
   memset(storage, 0, sizeof(grpc_linked_mdelem));
-  storage->md = grpc_mdelem_from_strings(key.c_str(), value.c_str());
+  storage->md = grpc_mdelem_from_strings(exec_ctx, key.c_str(), value.c_str());
   grpc_metadata_batch_link_head(batch_, storage);
   return storage;
 }
@@ -89,7 +90,8 @@
 
 namespace {
 
-bool MaybeAddFilter(grpc_channel_stack_builder *builder, void *arg) {
+bool MaybeAddFilter(grpc_exec_ctx *exec_ctx,
+                    grpc_channel_stack_builder *builder, void *arg) {
   const FilterRecord &filter = *(FilterRecord *)arg;
   if (filter.include_filter) {
     const grpc_channel_args *args =
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index e420efc..5de8f5e 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -70,7 +70,8 @@
   /// Adds metadata and returns the newly allocated storage.
   /// The caller takes ownership of the result, which must exist for the
   /// lifetime of the gRPC call.
-  grpc_linked_mdelem *AddMetadata(const string &key, const string &value);
+  grpc_linked_mdelem *AddMetadata(grpc_exec_ctx *exec_ctx, const string &key,
+                                  const string &value);
 
   class const_iterator : public std::iterator<std::bidirectional_iterator_tag,
                                               const grpc_mdelem> {
@@ -216,12 +217,13 @@
 /// Represents channel data.
 class ChannelData {
  public:
-  virtual ~ChannelData() {
-    if (peer_) gpr_free((void *)peer_);
-  }
+  virtual ~ChannelData() {}
 
-  /// Caller does NOT take ownership of result.
-  const char *peer() const { return peer_; }
+  /// Initializes the call data.
+  virtual grpc_error *Init(grpc_exec_ctx *exec_ctx,
+                           grpc_channel_element_args *args) {
+    return GRPC_ERROR_NONE;
+  }
 
   // TODO(roth): Find a way to avoid passing elem into these methods.
 
@@ -232,11 +234,7 @@
                        const grpc_channel_info *channel_info);
 
  protected:
-  /// Takes ownership of \a peer.
-  ChannelData(const grpc_channel_args &args, const char *peer) : peer_(peer) {}
-
- private:
-  const char *peer_;
+  ChannelData() {}
 };
 
 /// Represents call data.
@@ -245,7 +243,10 @@
   virtual ~CallData() {}
 
   /// Initializes the call data.
-  virtual grpc_error *Init() { return GRPC_ERROR_NONE; }
+  virtual grpc_error *Init(grpc_exec_ctx *exec_ctx, ChannelData *channel_data,
+                           grpc_call_element_args *args) {
+    return GRPC_ERROR_NONE;
+  }
 
   // TODO(roth): Find a way to avoid passing elem into these methods.
 
@@ -263,7 +264,7 @@
   virtual char *GetPeer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
 
  protected:
-  explicit CallData(const ChannelData &) {}
+  CallData() {}
 };
 
 namespace internal {
@@ -276,15 +277,11 @@
  public:
   static const size_t channel_data_size = sizeof(ChannelDataType);
 
-  static void InitChannelElement(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem,
-                                 grpc_channel_element_args *args) {
-    const char *peer =
-        args->optional_transport
-            ? grpc_transport_get_peer(exec_ctx, args->optional_transport)
-            : nullptr;
-    // Construct the object in the already-allocated memory.
-    new (elem->channel_data) ChannelDataType(*args->channel_args, peer);
+  static grpc_error *InitChannelElement(grpc_exec_ctx *exec_ctx,
+                                        grpc_channel_element *elem,
+                                        grpc_channel_element_args *args) {
+    ChannelDataType *channel_data = new (elem->channel_data) ChannelDataType();
+    return channel_data->Init(exec_ctx, args);
   }
 
   static void DestroyChannelElement(grpc_exec_ctx *exec_ctx,
@@ -312,11 +309,10 @@
   static grpc_error *InitCallElement(grpc_exec_ctx *exec_ctx,
                                      grpc_call_element *elem,
                                      grpc_call_element_args *args) {
-    const ChannelDataType &channel_data =
-        *(ChannelDataType *)elem->channel_data;
+    ChannelDataType *channel_data = (ChannelDataType *)elem->channel_data;
     // Construct the object in the already-allocated memory.
-    CallDataType *call_data = new (elem->call_data) CallDataType(channel_data);
-    return call_data->Init();
+    CallDataType *call_data = new (elem->call_data) CallDataType();
+    return call_data->Init(exec_ctx, channel_data, args);
   }
 
   static void DestroyCallElement(grpc_exec_ctx *exec_ctx,
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index 8b431c7..3364b8c 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -85,39 +85,53 @@
     public abstract partial class MathBase
     {
       /// <summary>
-      ///  Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
-      ///  and remainder.
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  DivMany accepts an arbitrary number of division args from the client stream
-      ///  and sends back the results in the reply stream.  The stream continues until
-      ///  the client closes its end; the server does the same after sending all the
-      ///  replies.  The stream ends immediately if either end aborts.
+      /// DivMany accepts an arbitrary number of division args from the client stream
+      /// and sends back the results in the reply stream.  The stream continues until
+      /// the client closes its end; the server does the same after sending all the
+      /// replies.  The stream ends immediately if either end aborts.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
-      ///  generates up to limit numbers; otherwise it continues until the call is
-      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
+      /// generates up to limit numbers; otherwise it continues until the call is
+      /// canceled.  Unlike Fib above, Fib has no final FibReply.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  Sum sums a stream of numbers, returning the final result once the stream
-      ///  is closed.
+      /// Sum sums a stream of numbers, returning the final result once the stream
+      /// is closed.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -149,87 +163,123 @@
       }
 
       /// <summary>
-      ///  Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
-      ///  and remainder.
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return Div(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
-      ///  and remainder.
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
       }
       /// <summary>
-      ///  Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
-      ///  and remainder.
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return DivAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
-      ///  and remainder.
+      /// Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient
+      /// and remainder.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_Div, null, options, request);
       }
       /// <summary>
-      ///  DivMany accepts an arbitrary number of division args from the client stream
-      ///  and sends back the results in the reply stream.  The stream continues until
-      ///  the client closes its end; the server does the same after sending all the
-      ///  replies.  The stream ends immediately if either end aborts.
+      /// DivMany accepts an arbitrary number of division args from the client stream
+      /// and sends back the results in the reply stream.  The stream continues until
+      /// the client closes its end; the server does the same after sending all the
+      /// replies.  The stream ends immediately if either end aborts.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return DivMany(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  DivMany accepts an arbitrary number of division args from the client stream
-      ///  and sends back the results in the reply stream.  The stream continues until
-      ///  the client closes its end; the server does the same after sending all the
-      ///  replies.  The stream ends immediately if either end aborts.
+      /// DivMany accepts an arbitrary number of division args from the client stream
+      /// and sends back the results in the reply stream.  The stream continues until
+      /// the client closes its end; the server does the same after sending all the
+      /// replies.  The stream ends immediately if either end aborts.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
       }
       /// <summary>
-      ///  Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
-      ///  generates up to limit numbers; otherwise it continues until the call is
-      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
+      /// generates up to limit numbers; otherwise it continues until the call is
+      /// canceled.  Unlike Fib above, Fib has no final FibReply.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return Fib(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
-      ///  generates up to limit numbers; otherwise it continues until the call is
-      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// Fib generates numbers in the Fibonacci sequence.  If FibArgs.limit > 0, Fib
+      /// generates up to limit numbers; otherwise it continues until the call is
+      /// canceled.  Unlike Fib above, Fib has no final FibReply.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
       {
         return CallInvoker.AsyncServerStreamingCall(__Method_Fib, null, options, request);
       }
       /// <summary>
-      ///  Sum sums a stream of numbers, returning the final result once the stream
-      ///  is closed.
+      /// Sum sums a stream of numbers, returning the final result once the stream
+      /// is closed.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return Sum(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Sum sums a stream of numbers, returning the final result once the stream
-      ///  is closed.
+      /// Sum sums a stream of numbers, returning the final result once the stream
+      /// is closed.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
       {
         return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options);
@@ -242,6 +292,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(MathBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index ad5cf11..020c2df 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -115,6 +115,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(HealthBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index d0bf0af..8b58622 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -76,17 +76,24 @@
     public abstract partial class MetricsServiceBase
     {
       /// <summary>
-      ///  Returns the values of all the gauges that are currently being maintained by
-      ///  the service
+      /// Returns the values of all the gauges that are currently being maintained by
+      /// the service
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  Returns the value of one gauge
+      /// Returns the value of one gauge
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -118,45 +125,69 @@
       }
 
       /// <summary>
-      ///  Returns the values of all the gauges that are currently being maintained by
-      ///  the service
+      /// Returns the values of all the gauges that are currently being maintained by
+      /// the service
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return GetAllGauges(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Returns the values of all the gauges that are currently being maintained by
-      ///  the service
+      /// Returns the values of all the gauges that are currently being maintained by
+      /// the service
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options)
       {
         return CallInvoker.AsyncServerStreamingCall(__Method_GetAllGauges, null, options, request);
       }
       /// <summary>
-      ///  Returns the value of one gauge
+      /// Returns the value of one gauge
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return GetGauge(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Returns the value of one gauge
+      /// Returns the value of one gauge
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_GetGauge, null, options, request);
       }
       /// <summary>
-      ///  Returns the value of one gauge
+      /// Returns the value of one gauge
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return GetGaugeAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Returns the value of one gauge
+      /// Returns the value of one gauge
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_GetGauge, null, options, request);
@@ -169,6 +200,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index 3cc4ed9..5135d9a 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -71,18 +71,25 @@
     public abstract partial class BenchmarkServiceBase
     {
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -114,49 +121,71 @@
       }
 
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return StreamingCall(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response.
-      ///  The server returns the client payload as-is.
+      /// One request followed by one response.
+      /// The server returns the client payload as-is.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_StreamingCall, null, options);
@@ -169,6 +198,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
@@ -227,42 +257,56 @@
     public abstract partial class WorkerServiceBase
     {
       /// <summary>
-      ///  Start server with specified workload.
-      ///  First request sent specifies the ServerConfig followed by ServerStatus
-      ///  response. After that, a "Mark" can be sent anytime to request the latest
-      ///  stats. Closing the stream will initiate shutdown of the test server
-      ///  and once the shutdown has finished, the OK status is sent to terminate
-      ///  this RPC.
+      /// Start server with specified workload.
+      /// First request sent specifies the ServerConfig followed by ServerStatus
+      /// response. After that, a "Mark" can be sent anytime to request the latest
+      /// stats. Closing the stream will initiate shutdown of the test server
+      /// and once the shutdown has finished, the OK status is sent to terminate
+      /// this RPC.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  Start client with specified workload.
-      ///  First request sent specifies the ClientConfig followed by ClientStatus
-      ///  response. After that, a "Mark" can be sent anytime to request the latest
-      ///  stats. Closing the stream will initiate shutdown of the test client
-      ///  and once the shutdown has finished, the OK status is sent to terminate
-      ///  this RPC.
+      /// Start client with specified workload.
+      /// First request sent specifies the ClientConfig followed by ClientStatus
+      /// response. After that, a "Mark" can be sent anytime to request the latest
+      /// stats. Closing the stream will initiate shutdown of the test client
+      /// and once the shutdown has finished, the OK status is sent to terminate
+      /// this RPC.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  Just return the core count - unary call
+      /// Just return the core count - unary call
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  Quit this worker
+      /// Quit this worker
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -294,105 +338,149 @@
       }
 
       /// <summary>
-      ///  Start server with specified workload.
-      ///  First request sent specifies the ServerConfig followed by ServerStatus
-      ///  response. After that, a "Mark" can be sent anytime to request the latest
-      ///  stats. Closing the stream will initiate shutdown of the test server
-      ///  and once the shutdown has finished, the OK status is sent to terminate
-      ///  this RPC.
+      /// Start server with specified workload.
+      /// First request sent specifies the ServerConfig followed by ServerStatus
+      /// response. After that, a "Mark" can be sent anytime to request the latest
+      /// stats. Closing the stream will initiate shutdown of the test server
+      /// and once the shutdown has finished, the OK status is sent to terminate
+      /// this RPC.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return RunServer(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Start server with specified workload.
-      ///  First request sent specifies the ServerConfig followed by ServerStatus
-      ///  response. After that, a "Mark" can be sent anytime to request the latest
-      ///  stats. Closing the stream will initiate shutdown of the test server
-      ///  and once the shutdown has finished, the OK status is sent to terminate
-      ///  this RPC.
+      /// Start server with specified workload.
+      /// First request sent specifies the ServerConfig followed by ServerStatus
+      /// response. After that, a "Mark" can be sent anytime to request the latest
+      /// stats. Closing the stream will initiate shutdown of the test server
+      /// and once the shutdown has finished, the OK status is sent to terminate
+      /// this RPC.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_RunServer, null, options);
       }
       /// <summary>
-      ///  Start client with specified workload.
-      ///  First request sent specifies the ClientConfig followed by ClientStatus
-      ///  response. After that, a "Mark" can be sent anytime to request the latest
-      ///  stats. Closing the stream will initiate shutdown of the test client
-      ///  and once the shutdown has finished, the OK status is sent to terminate
-      ///  this RPC.
+      /// Start client with specified workload.
+      /// First request sent specifies the ClientConfig followed by ClientStatus
+      /// response. After that, a "Mark" can be sent anytime to request the latest
+      /// stats. Closing the stream will initiate shutdown of the test client
+      /// and once the shutdown has finished, the OK status is sent to terminate
+      /// this RPC.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return RunClient(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Start client with specified workload.
-      ///  First request sent specifies the ClientConfig followed by ClientStatus
-      ///  response. After that, a "Mark" can be sent anytime to request the latest
-      ///  stats. Closing the stream will initiate shutdown of the test client
-      ///  and once the shutdown has finished, the OK status is sent to terminate
-      ///  this RPC.
+      /// Start client with specified workload.
+      /// First request sent specifies the ClientConfig followed by ClientStatus
+      /// response. After that, a "Mark" can be sent anytime to request the latest
+      /// stats. Closing the stream will initiate shutdown of the test client
+      /// and once the shutdown has finished, the OK status is sent to terminate
+      /// this RPC.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_RunClient, null, options);
       }
       /// <summary>
-      ///  Just return the core count - unary call
+      /// Just return the core count - unary call
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return CoreCount(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Just return the core count - unary call
+      /// Just return the core count - unary call
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_CoreCount, null, options, request);
       }
       /// <summary>
-      ///  Just return the core count - unary call
+      /// Just return the core count - unary call
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return CoreCountAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Just return the core count - unary call
+      /// Just return the core count - unary call
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_CoreCount, null, options, request);
       }
       /// <summary>
-      ///  Quit this worker
+      /// Quit this worker
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return QuitWorker(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Quit this worker
+      /// Quit this worker
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_QuitWorker, null, options, request);
       }
       /// <summary>
-      ///  Quit this worker
+      /// Quit this worker
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return QuitWorkerAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  Quit this worker
+      /// Quit this worker
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_QuitWorker, null, options, request);
@@ -405,6 +493,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 43dbc28..0265f8e 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -42,8 +42,8 @@
 
 namespace Grpc.Testing {
   /// <summary>
-  ///  A simple service to test the various types of RPCs and experiment with
-  ///  performance with various types of payload.
+  /// A simple service to test the various types of RPCs and experiment with
+  /// performance with various types of payload.
   /// </summary>
   public static partial class TestService
   {
@@ -123,74 +123,101 @@
     public abstract partial class TestServiceBase
     {
       /// <summary>
-      ///  One empty request followed by one empty response.
+      /// One empty request followed by one empty response.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  One request followed by one response.
+      /// One request followed by one response.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  One request followed by one response. Response has cache control
-      ///  headers set such that a caching HTTP proxy (such as GFE) can
-      ///  satisfy subsequent requests.
+      /// One request followed by one response. Response has cache control
+      /// headers set such that a caching HTTP proxy (such as GFE) can
+      /// satisfy subsequent requests.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.SimpleResponse> CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  One request followed by a sequence of responses (streamed download).
-      ///  The server returns the payload with client desired type and sizes.
+      /// One request followed by a sequence of responses (streamed download).
+      /// The server returns the payload with client desired type and sizes.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  A sequence of requests followed by one response (streamed upload).
-      ///  The server returns the aggregated size of client payload as the result.
+      /// A sequence of requests followed by one response (streamed upload).
+      /// The server returns the aggregated size of client payload as the result.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  A sequence of requests with each request served by the server immediately.
-      ///  As one request could lead to multiple responses, this interface
-      ///  demonstrates the idea of full duplexing.
+      /// A sequence of requests with each request served by the server immediately.
+      /// As one request could lead to multiple responses, this interface
+      /// demonstrates the idea of full duplexing.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  A sequence of requests followed by a sequence of responses.
-      ///  The server buffers all the client requests and then serves them in order. A
-      ///  stream of responses are returned to the client when the server starts with
-      ///  first request.
+      /// A sequence of requests followed by a sequence of responses.
+      /// The server buffers all the client requests and then serves them in order. A
+      /// stream of responses are returned to the client when the server starts with
+      /// first request.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
       /// <summary>
-      ///  The test server will not implement this method. It will be used
-      ///  to test the behavior when clients call unimplemented methods.
+      /// The test server will not implement this method. It will be used
+      /// to test the behavior when clients call unimplemented methods.
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -222,195 +249,285 @@
       }
 
       /// <summary>
-      ///  One empty request followed by one empty response.
+      /// One empty request followed by one empty response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return EmptyCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One empty request followed by one empty response.
+      /// One empty request followed by one empty response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_EmptyCall, null, options, request);
       }
       /// <summary>
-      ///  One empty request followed by one empty response.
+      /// One empty request followed by one empty response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return EmptyCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One empty request followed by one empty response.
+      /// One empty request followed by one empty response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_EmptyCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by one response.
+      /// One request followed by one response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response.
+      /// One request followed by one response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by one response.
+      /// One request followed by one response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response.
+      /// One request followed by one response.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by one response. Response has cache control
-      ///  headers set such that a caching HTTP proxy (such as GFE) can
-      ///  satisfy subsequent requests.
+      /// One request followed by one response. Response has cache control
+      /// headers set such that a caching HTTP proxy (such as GFE) can
+      /// satisfy subsequent requests.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.SimpleResponse CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return CacheableUnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response. Response has cache control
-      ///  headers set such that a caching HTTP proxy (such as GFE) can
-      ///  satisfy subsequent requests.
+      /// One request followed by one response. Response has cache control
+      /// headers set such that a caching HTTP proxy (such as GFE) can
+      /// satisfy subsequent requests.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.SimpleResponse CacheableUnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_CacheableUnaryCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by one response. Response has cache control
-      ///  headers set such that a caching HTTP proxy (such as GFE) can
-      ///  satisfy subsequent requests.
+      /// One request followed by one response. Response has cache control
+      /// headers set such that a caching HTTP proxy (such as GFE) can
+      /// satisfy subsequent requests.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> CacheableUnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return CacheableUnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by one response. Response has cache control
-      ///  headers set such that a caching HTTP proxy (such as GFE) can
-      ///  satisfy subsequent requests.
+      /// One request followed by one response. Response has cache control
+      /// headers set such that a caching HTTP proxy (such as GFE) can
+      /// satisfy subsequent requests.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> CacheableUnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_CacheableUnaryCall, null, options, request);
       }
       /// <summary>
-      ///  One request followed by a sequence of responses (streamed download).
-      ///  The server returns the payload with client desired type and sizes.
+      /// One request followed by a sequence of responses (streamed download).
+      /// The server returns the payload with client desired type and sizes.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return StreamingOutputCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  One request followed by a sequence of responses (streamed download).
-      ///  The server returns the payload with client desired type and sizes.
+      /// One request followed by a sequence of responses (streamed download).
+      /// The server returns the payload with client desired type and sizes.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
       {
         return CallInvoker.AsyncServerStreamingCall(__Method_StreamingOutputCall, null, options, request);
       }
       /// <summary>
-      ///  A sequence of requests followed by one response (streamed upload).
-      ///  The server returns the aggregated size of client payload as the result.
+      /// A sequence of requests followed by one response (streamed upload).
+      /// The server returns the aggregated size of client payload as the result.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return StreamingInputCall(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  A sequence of requests followed by one response (streamed upload).
-      ///  The server returns the aggregated size of client payload as the result.
+      /// A sequence of requests followed by one response (streamed upload).
+      /// The server returns the aggregated size of client payload as the result.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
       {
         return CallInvoker.AsyncClientStreamingCall(__Method_StreamingInputCall, null, options);
       }
       /// <summary>
-      ///  A sequence of requests with each request served by the server immediately.
-      ///  As one request could lead to multiple responses, this interface
-      ///  demonstrates the idea of full duplexing.
+      /// A sequence of requests with each request served by the server immediately.
+      /// As one request could lead to multiple responses, this interface
+      /// demonstrates the idea of full duplexing.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return FullDuplexCall(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  A sequence of requests with each request served by the server immediately.
-      ///  As one request could lead to multiple responses, this interface
-      ///  demonstrates the idea of full duplexing.
+      /// A sequence of requests with each request served by the server immediately.
+      /// As one request could lead to multiple responses, this interface
+      /// demonstrates the idea of full duplexing.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_FullDuplexCall, null, options);
       }
       /// <summary>
-      ///  A sequence of requests followed by a sequence of responses.
-      ///  The server buffers all the client requests and then serves them in order. A
-      ///  stream of responses are returned to the client when the server starts with
-      ///  first request.
+      /// A sequence of requests followed by a sequence of responses.
+      /// The server buffers all the client requests and then serves them in order. A
+      /// stream of responses are returned to the client when the server starts with
+      /// first request.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return HalfDuplexCall(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  A sequence of requests followed by a sequence of responses.
-      ///  The server buffers all the client requests and then serves them in order. A
-      ///  stream of responses are returned to the client when the server starts with
-      ///  first request.
+      /// A sequence of requests followed by a sequence of responses.
+      /// The server buffers all the client requests and then serves them in order. A
+      /// stream of responses are returned to the client when the server starts with
+      /// first request.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_HalfDuplexCall, null, options);
       }
       /// <summary>
-      ///  The test server will not implement this method. It will be used
-      ///  to test the behavior when clients call unimplemented methods.
+      /// The test server will not implement this method. It will be used
+      /// to test the behavior when clients call unimplemented methods.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnimplementedCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  The test server will not implement this method. It will be used
-      ///  to test the behavior when clients call unimplemented methods.
+      /// The test server will not implement this method. It will be used
+      /// to test the behavior when clients call unimplemented methods.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnimplementedCall, null, options, request);
       }
       /// <summary>
-      ///  The test server will not implement this method. It will be used
-      ///  to test the behavior when clients call unimplemented methods.
+      /// The test server will not implement this method. It will be used
+      /// to test the behavior when clients call unimplemented methods.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnimplementedCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  The test server will not implement this method. It will be used
-      ///  to test the behavior when clients call unimplemented methods.
+      /// The test server will not implement this method. It will be used
+      /// to test the behavior when clients call unimplemented methods.
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request);
@@ -423,6 +540,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
@@ -438,8 +556,8 @@
 
   }
   /// <summary>
-  ///  A simple service NOT implemented at servers so clients can test for
-  ///  that case.
+  /// A simple service NOT implemented at servers so clients can test for
+  /// that case.
   /// </summary>
   public static partial class UnimplementedService
   {
@@ -464,8 +582,11 @@
     public abstract partial class UnimplementedServiceBase
     {
       /// <summary>
-      ///  A call that no server should implement
+      /// A call that no server should implement
       /// </summary>
+      /// <param name="request">The request received from the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>The response to send back to the client (wrapped by a task).</returns>
       public virtual global::System.Threading.Tasks.Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -497,29 +618,45 @@
       }
 
       /// <summary>
-      ///  A call that no server should implement
+      /// A call that no server should implement
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnimplementedCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  A call that no server should implement
+      /// A call that no server should implement
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The response received from the server.</returns>
       public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnimplementedCall, null, options, request);
       }
       /// <summary>
-      ///  A call that no server should implement
+      /// A call that no server should implement
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnimplementedCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  A call that no server should implement
+      /// A call that no server should implement
       /// </summary>
+      /// <param name="request">The request to send to the server.</param>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request);
@@ -532,6 +669,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
@@ -540,7 +678,7 @@
 
   }
   /// <summary>
-  ///  A service used to control reconnect server.
+  /// A service used to control reconnect server.
   /// </summary>
   public static partial class ReconnectService
   {
@@ -648,6 +786,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
diff --git a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
index 1b6f96c..5bd7558 100644
--- a/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
+++ b/src/csharp/Grpc.Reflection/ReflectionGrpc.cs
@@ -64,9 +64,13 @@
     public abstract partial class ServerReflectionBase
     {
       /// <summary>
-      ///  The reflection service is structured as a bidirectional stream, ensuring
-      ///  all related requests go to a single server.
+      /// The reflection service is structured as a bidirectional stream, ensuring
+      /// all related requests go to a single server.
       /// </summary>
+      /// <param name="requestStream">Used for reading requests from the client.</param>
+      /// <param name="responseStream">Used for sending responses back to the client.</param>
+      /// <param name="context">The context of the server-side call handler being invoked.</param>
+      /// <returns>A task indicating completion of the handler.</returns>
       public virtual global::System.Threading.Tasks.Task ServerReflectionInfo(IAsyncStreamReader<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest> requestStream, IServerStreamWriter<global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -98,17 +102,23 @@
       }
 
       /// <summary>
-      ///  The reflection service is structured as a bidirectional stream, ensuring
-      ///  all related requests go to a single server.
+      /// The reflection service is structured as a bidirectional stream, ensuring
+      /// all related requests go to a single server.
       /// </summary>
+      /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
+      /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
+      /// <param name="cancellationToken">An optional token for canceling the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return ServerReflectionInfo(new CallOptions(headers, deadline, cancellationToken));
       }
       /// <summary>
-      ///  The reflection service is structured as a bidirectional stream, ensuring
-      ///  all related requests go to a single server.
+      /// The reflection service is structured as a bidirectional stream, ensuring
+      /// all related requests go to a single server.
       /// </summary>
+      /// <param name="options">The options for the call.</param>
+      /// <returns>The call object.</returns>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Reflection.V1Alpha.ServerReflectionRequest, global::Grpc.Reflection.V1Alpha.ServerReflectionResponse> ServerReflectionInfo(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_ServerReflectionInfo, null, options);
@@ -121,6 +131,7 @@
     }
 
     /// <summary>Creates service definition that can be registered with a server</summary>
+    /// <param name="serviceImpl">An object implementing the server-side handling logic.</param>
     public static ServerServiceDefinition BindService(ServerReflectionBase serviceImpl)
     {
       return ServerServiceDefinition.CreateBuilder()
diff --git a/src/node/ext/completion_queue.h b/src/node/ext/completion_queue.h
index bf280f7..9b01028 100644
--- a/src/node/ext/completion_queue.h
+++ b/src/node/ext/completion_queue.h
@@ -32,6 +32,7 @@
  */
 
 #include <v8.h>
+#include <grpc/grpc.h>
 
 namespace grpc {
 namespace node {
diff --git a/src/node/ext/completion_queue_async_worker.cc b/src/node/ext/completion_queue_threadpool.cc
similarity index 72%
rename from src/node/ext/completion_queue_async_worker.cc
rename to src/node/ext/completion_queue_threadpool.cc
index f5e03b2..6302e7a 100644
--- a/src/node/ext/completion_queue_async_worker.cc
+++ b/src/node/ext/completion_queue_threadpool.cc
@@ -31,18 +31,63 @@
  *
  */
 
+/* I don't like using #ifndef, but I don't see a better way to do this */
+#ifndef GRPC_UV
+
 #include <node.h>
 #include <nan.h>
 
 #include "grpc/grpc.h"
 #include "grpc/support/log.h"
 #include "grpc/support/time.h"
-#include "completion_queue_async_worker.h"
+#include "completion_queue.h"
 #include "call.h"
 
 namespace grpc {
 namespace node {
 
+namespace {
+
+/* A worker that asynchronously calls completion_queue_next, and queues onto the
+   node event loop a call to the function stored in the event's tag. */
+class CompletionQueueAsyncWorker : public Nan::AsyncWorker {
+ public:
+  CompletionQueueAsyncWorker();
+
+  ~CompletionQueueAsyncWorker();
+  /* Calls completion_queue_next with the provided deadline, and stores the
+     event if there was one or sets an error message if there was not */
+  void Execute();
+
+  /* Returns the completion queue attached to this class */
+  static grpc_completion_queue *GetQueue();
+
+  /* Convenience function to create a worker with the given arguments and queue
+     it to run asynchronously */
+  static void Next();
+
+  /* Initialize the CompletionQueueAsyncWorker class */
+  static void Init(v8::Local<v8::Object> exports);
+
+ protected:
+  /* Called when Execute has succeeded (completed without setting an error
+     message). Calls the saved callback with the event that came from
+     completion_queue_next */
+  void HandleOKCallback();
+
+  void HandleErrorCallback();
+
+ private:
+  grpc_event result;
+
+  static grpc_completion_queue *queue;
+
+  // Number of grpc_completion_queue_next calls in the thread pool
+  static int current_threads;
+  // Number of grpc_completion_queue_next calls waiting to enter the thread pool
+  static int waiting_next_calls;
+};
+
 const int max_queue_threads = 2;
 
 using v8::Function;
@@ -137,5 +182,21 @@
   DestroyTag(result.tag);
 }
 
+}  // namespace
+
+grpc_completion_queue *GetCompletionQueue() {
+  return CompletionQueueAsyncWorker::GetQueue();
+}
+
+void CompletionQueueNext() {
+  CompletionQueueAsyncWorker::Next();
+}
+
+void CompletionQueueInit(Local<Object> exports) {
+  CompletionQueueAsyncWorker::Init(exports);
+}
+
 }  // namespace node
 }  // namespace grpc
+
+#endif  /* GRPC_UV */
diff --git a/src/node/ext/completion_queue.cc b/src/node/ext/completion_queue_uv.cc
similarity index 92%
rename from src/node/ext/completion_queue.cc
rename to src/node/ext/completion_queue_uv.cc
index fcfa77b..615973a 100644
--- a/src/node/ext/completion_queue.cc
+++ b/src/node/ext/completion_queue_uv.cc
@@ -31,6 +31,8 @@
  *
  */
 
+#ifdef GRPC_UV
+
 #include <uv.h>
 #include <node.h>
 #include <v8.h>
@@ -38,7 +40,6 @@
 
 #include "call.h"
 #include "completion_queue.h"
-#include "completion_queue_async_worker.h"
 
 namespace grpc {
 namespace node {
@@ -81,34 +82,24 @@
 }
 
 grpc_completion_queue *GetCompletionQueue() {
-#ifdef GRPC_UV
   return queue;
-#else
-  return CompletionQueueAsyncWorker::GetQueue();
-#endif
 }
 
 void CompletionQueueNext() {
-#ifdef GRPC_UV
   if (pending_batches == 0) {
     GPR_ASSERT(!uv_is_active((uv_handle_t *)&prepare));
     uv_prepare_start(&prepare, drain_completion_queue);
   }
   pending_batches++;
-#else
-  CompletionQueueAsyncWorker::Next();
-#endif
 }
 
 void CompletionQueueInit(Local<Object> exports) {
-#ifdef GRPC_UV
   queue = grpc_completion_queue_create(NULL);
   uv_prepare_init(uv_default_loop(), &prepare);
   pending_batches = 0;
-#else
-  CompletionQueueAsyncWorker::Init(exports);
-#endif
 }
 
 }  // namespace node
 }  // namespace grpc
+
+#endif /* GRPC_UV */
diff --git a/src/node/interop/interop_client.js b/src/node/interop/interop_client.js
index 46ddecf..75cfb41 100644
--- a/src/node/interop/interop_client.js
+++ b/src/node/interop/interop_client.js
@@ -312,6 +312,9 @@
     }
   };
   var streaming_arg = {
+    response_parameters: [
+     {size: 314159}
+    ],
     payload: {
       body: zeroBuffer(271828)
     }
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 9c1562e..134ef23 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -99,7 +99,18 @@
 function _write(chunk, encoding, callback) {
   /* jshint validthis: true */
   var batch = {};
-  var message = this.serialize(chunk);
+  var message;
+  try {
+    message = this.serialize(chunk);
+  } catch (e) {
+    /* Sending this error to the server and emitting it immediately on the
+       client may put the call in a slightly weird state on the client side,
+       but passing an object that causes a serialization failure is a misuse
+       of the API anyway, so that's OK. The primary purpose here is to give the
+       programmer a useful error and to stop the stream properly */
+    this.call.cancelWithStatus(grpc.status.INTERNAL, "Serialization failure");
+    callback(e);
+  }
   if (_.isFinite(encoding)) {
     /* Attach the encoding if it is a finite number. This is the closest we
      * can get to checking that it is valid flags */
@@ -184,14 +195,15 @@
     } else {
       status = this.received_status;
     }
-    this.emit('status', status);
-    if (status.code !== grpc.status.OK) {
+    if (status.code === grpc.status.OK) {
+      this.push(null);
+    } else {
       var error = new Error(status.details);
       error.code = status.code;
       error.metadata = status.metadata;
       this.emit('error', error);
-      return;
     }
+    this.emit('status', status);
   }
 }
 
@@ -224,9 +236,11 @@
     } catch (e) {
       self._readsDone({code: grpc.status.INTERNAL,
                        details: 'Failed to parse server response'});
+      return;
     }
     if (data === null) {
       self._readsDone();
+      return;
     }
     if (self.push(deserialized) && data !== null) {
       var read_batch = {};
@@ -396,6 +410,8 @@
       var status = response.status;
       var error;
       var deserialized;
+      emitter.emit('metadata', Metadata._fromCoreRepresentation(
+          response.metadata));
       if (status.code === grpc.status.OK) {
         if (err) {
           // Got a batch error, but OK status. Something went wrong
@@ -423,8 +439,6 @@
         args.callback(null, deserialized);
       }
       emitter.emit('status', status);
-      emitter.emit('metadata', Metadata._fromCoreRepresentation(
-          response.metadata));
     });
     return emitter;
   }
diff --git a/src/node/src/server.js b/src/node/src/server.js
index b3b4149..da9c6b2 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -127,7 +127,14 @@
         (new Metadata())._getCoreRepresentation();
     call.metadataSent = true;
   }
-  var message = serialize(value);
+  var message;
+  try {
+    message = serialize(value);
+  } catch (e) {
+    e.code = grpc.status.INTERNAL;
+    handleError(e);
+    return;
+  }
   message.grpcWriteFlags = flags;
   end_batch[grpc.opType.SEND_MESSAGE] = message;
   end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status;
@@ -278,7 +285,14 @@
         (new Metadata())._getCoreRepresentation();
     this.call.metadataSent = true;
   }
-  var message = this.serialize(chunk);
+  var message;
+  try {
+    message = this.serialize(chunk);
+  } catch (e) {
+    e.code = grpc.status.INTERNAL;
+    callback(e);
+    return;
+  }
   if (_.isFinite(encoding)) {
     /* Attach the encoding if it is a finite number. This is the closest we
      * can get to checking that it is valid flags */
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index d8b36dc..e429a36 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -179,20 +179,22 @@
       call.on('data', function(value) {
         assert.fail('No messages expected');
       });
-      call.on('status', function(status) {
-        assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
+      call.on('error', function(err) {
+        assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
         done();
       });
+      call.on('error', function(status) { /* Do nothing */ });
     });
     it('should respond to a bidi call with UNIMPLEMENTED', function(done) {
       var call = client.divMany();
       call.on('data', function(value) {
         assert.fail('No messages expected');
       });
-      call.on('status', function(status) {
-        assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
+      call.on('error', function(err) {
+        assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED);
         done();
       });
+      call.on('error', function(status) { /* Do nothing */ });
       call.end();
     });
   });
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index 6e594fd..bcc2bb6 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -36,7 +36,7 @@
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCPlugin'
-  v = '1.0.1'
+  v = '1.0.2'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
@@ -84,7 +84,10 @@
   repo = 'grpc/grpc'
   file = "grpc_objective_c_plugin-#{v}-macos-x86_64.zip"
   s.source = {
-    :http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}",
+    # TODO(mxyan): Change back to "https://github.com/#{repo}/releases/download/v#{v}/#{file}" for
+    # next release
+    # :http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}",
+    :http => "https://github.com/#{repo}/releases/download/objective-c-v#{v}/#{file}",
     # TODO(jcanizales): Add sha1 or sha256
     # :sha1 => '??',
   }
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 31065cb..450bec3 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -50,7 +50,7 @@
 
 // TODO(jcanizales): Generate the version in a standalone header, from templates. Like
 // templates/src/core/surface/version.c.template .
-#define GRPC_OBJC_VERSION_STRING @"1.0.1"
+#define GRPC_OBJC_VERSION_STRING @"1.0.2"
 
 static NSMutableDictionary *kHostCache;
 
diff --git a/src/php/bin/generate_proto_php.sh b/src/php/bin/generate_proto_php.sh
index c558bc5..416fa9d 100755
--- a/src/php/bin/generate_proto_php.sh
+++ b/src/php/bin/generate_proto_php.sh
@@ -39,10 +39,13 @@
 
 # replace the Empty message with EmptyMessage
 # because Empty is a PHP reserved word
-sed -i 's/message Empty/message EmptyMessage/g' \
-    src/proto/grpc/testing/empty.proto
-sed -i 's/grpc\.testing\.Empty/grpc\.testing\.EmptyMessage/g' \
-    src/proto/grpc/testing/test.proto
+output_file=$(mktemp)
+sed 's/message Empty/message EmptyMessage/g' \
+  src/proto/grpc/testing/empty.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/empty.proto
+sed 's/grpc\.testing\.Empty/grpc\.testing\.EmptyMessage/g' \
+  src/proto/grpc/testing/test.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/test.proto
 
 protoc --proto_path=. \
        --php_out=src/php/tests/interop \
@@ -53,7 +56,10 @@
        src/proto/grpc/testing/test.proto
 
 # change it back
-sed -i 's/message EmptyMessage/message Empty/g' \
-    src/proto/grpc/testing/empty.proto
-sed -i 's/grpc\.testing\.EmptyMessage/grpc\.testing\.Empty/g' \
-    src/proto/grpc/testing/test.proto
+sed 's/message EmptyMessage/message Empty/g' \
+  src/proto/grpc/testing/empty.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/empty.proto
+sed 's/grpc\.testing\.EmptyMessage/grpc\.testing\.Empty/g' \
+  src/proto/grpc/testing/test.proto > $output_file
+mv $output_file ./src/proto/grpc/testing/test.proto
+
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 3a49ea8..64b1137 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -478,6 +478,7 @@
                                    true);
       add_property_zval(result, "status", recv_status);
       PHP_GRPC_DELREF(recv_status);
+      PHP_GRPC_FREE_STD_ZVAL(recv_status);
       break;
     case GRPC_OP_RECV_CLOSE_ON_SERVER:
       add_property_bool(result, "cancelled", cancelled);
@@ -501,6 +502,7 @@
     }
     if (ops[i].op == GRPC_OP_RECV_MESSAGE) {
       grpc_byte_buffer_destroy(message);
+      PHP_GRPC_FREE_STD_ZVAL(message_str);
     }
   }
   RETURN_DESTROY_ZVAL(result);
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 3aafc3a..043817f 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -111,9 +111,7 @@
   grpc_call_credentials *creds =
       grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
                                              NULL);
-  zval *creds_object;
-  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
-  creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
+  zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
@@ -155,9 +153,7 @@
 
   grpc_call_credentials *creds =
     grpc_metadata_credentials_create_from_plugin(plugin, NULL);
-  zval *creds_object;
-  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
-  creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
+  zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
@@ -211,6 +207,8 @@
   plugin_state *state = (plugin_state *)ptr;
   efree(state->fci);
   efree(state->fci_cache);
+  PHP_GRPC_FREE_STD_ZVAL(state->fci->params);
+  PHP_GRPC_FREE_STD_ZVAL(state->fci->retval);
   efree(state);
 }
 
diff --git a/src/php/ext/grpc/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
index a32c4a4..36a8223 100644
--- a/src/php/ext/grpc/channel_credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -121,9 +121,7 @@
  */
 PHP_METHOD(ChannelCredentials, createDefault) {
   grpc_channel_credentials *creds = grpc_google_default_credentials_create();
-  zval *creds_object;
-  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
-  creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
+  zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
@@ -160,9 +158,7 @@
   grpc_channel_credentials *creds = grpc_ssl_credentials_create(
       pem_root_certs,
       pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
-  zval *creds_object;
-  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
-  creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
+  zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
@@ -191,9 +187,7 @@
   grpc_channel_credentials *creds =
       grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped,
                                                 NULL);
-  zval *creds_object;
-  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
-  creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
+  zval *creds_object = grpc_php_wrap_channel_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
diff --git a/src/php/ext/grpc/php7_wrapper.h b/src/php/ext/grpc/php7_wrapper.h
index 1d78241..72e982d 100644
--- a/src/php/ext/grpc/php7_wrapper.h
+++ b/src/php/ext/grpc/php7_wrapper.h
@@ -50,8 +50,13 @@
 
 #define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val, dup)
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) MAKE_STD_ZVAL(pzv)
+#define PHP_GRPC_FREE_STD_ZVAL(pzv)
 #define PHP_GRPC_DELREF(zv) Z_DELREF_P(zv)
 
+#define RETURN_DESTROY_ZVAL(val) \
+  RETURN_ZVAL(val, false /* Don't execute copy constructor */, \
+              true /* Dealloc original before returning */)
+
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
   typedef struct name { \
     zend_object std;
@@ -144,8 +149,15 @@
 #define PHP_GRPC_RETURN_STRING(val, dup) RETURN_STRING(val)
 #define PHP_GRPC_MAKE_STD_ZVAL(pzv) \
   pzv = (zval *)emalloc(sizeof(zval));
+#define PHP_GRPC_FREE_STD_ZVAL(pzv) efree(pzv);
 #define PHP_GRPC_DELREF(zv)
 
+#define RETURN_DESTROY_ZVAL(val) \
+  RETVAL_ZVAL(val, false /* Don't execute copy constructor */, \
+              true /* Dealloc original before returning */); \
+  efree(val); \
+  return
+
 #define PHP_GRPC_WRAP_OBJECT_START(name) \
   typedef struct name {
 #define PHP_GRPC_WRAP_OBJECT_END(name) \
diff --git a/src/php/ext/grpc/php_grpc.h b/src/php/ext/grpc/php_grpc.h
index e57a065..13083b0 100644
--- a/src/php/ext/grpc/php_grpc.h
+++ b/src/php/ext/grpc/php_grpc.h
@@ -61,10 +61,6 @@
 
 #include "grpc/grpc.h"
 
-#define RETURN_DESTROY_ZVAL(val)                               \
-  RETURN_ZVAL(val, false /* Don't execute copy constructor */, \
-              true /* Dealloc original before returning */)
-
 /* These are all function declarations */
 /* Code that runs at module initialization */
 PHP_MINIT_FUNCTION(grpc);
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index 1610c8e..3e39fee 100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -113,9 +113,7 @@
   grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex(
       pem_root_certs, &pem_key_cert_pair, 1,
       GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, NULL);
-  zval *creds_object;
-  PHP_GRPC_MAKE_STD_ZVAL(creds_object);
-  creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
+  zval *creds_object = grpc_php_wrap_server_credentials(creds TSRMLS_CC);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 945231b..7ada915 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -115,11 +115,9 @@
   }
   wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
   wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
-  zval *sum;
-  PHP_GRPC_MAKE_STD_ZVAL(sum);
-  sum =
-      grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
-                            TSRMLS_CC);
+  zval *sum =
+    grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped)
+                          TSRMLS_CC);
   RETURN_DESTROY_ZVAL(sum);
 }
 
@@ -141,11 +139,9 @@
   }
   wrapped_grpc_timeval *self = Z_WRAPPED_GRPC_TIMEVAL_P(getThis());
   wrapped_grpc_timeval *other = Z_WRAPPED_GRPC_TIMEVAL_P(other_obj);
-  zval *diff;
-  PHP_GRPC_MAKE_STD_ZVAL(diff);
-  diff =
-      grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
-                            TSRMLS_CC);
+  zval *diff =
+    grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped)
+                          TSRMLS_CC);
   RETURN_DESTROY_ZVAL(diff);
 }
 
@@ -206,9 +202,7 @@
  * @return Timeval The current time
  */
 PHP_METHOD(Timeval, now) {
-  zval *now;
-  PHP_GRPC_MAKE_STD_ZVAL(now);
-  now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
+  zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(now);
 }
 
@@ -217,13 +211,9 @@
  * @return Timeval Zero length time interval
  */
 PHP_METHOD(Timeval, zero) {
-  zval *grpc_php_timeval_zero;
-  PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_zero);
-  grpc_php_timeval_zero =
-      grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
-  RETURN_ZVAL(grpc_php_timeval_zero,
-              false, /* Copy original before returning? */
-              true /* Destroy original before returning */);
+  zval *grpc_php_timeval_zero =
+    grpc_php_wrap_timeval(gpr_time_0(GPR_CLOCK_REALTIME) TSRMLS_CC);
+  RETURN_DESTROY_ZVAL(grpc_php_timeval_zero);
 }
 
 /**
@@ -231,10 +221,8 @@
  * @return Timeval Infinite future time value
  */
 PHP_METHOD(Timeval, infFuture) {
-  zval *grpc_php_timeval_inf_future;
-  PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_inf_future);
-  grpc_php_timeval_inf_future =
-      grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
+  zval *grpc_php_timeval_inf_future =
+    grpc_php_wrap_timeval(gpr_inf_future(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
 }
 
@@ -243,10 +231,8 @@
  * @return Timeval Infinite past time value
  */
 PHP_METHOD(Timeval, infPast) {
-  zval *grpc_php_timeval_inf_past;
-  PHP_GRPC_MAKE_STD_ZVAL(grpc_php_timeval_inf_past);
-  grpc_php_timeval_inf_past =
-      grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
+  zval *grpc_php_timeval_inf_past =
+    grpc_php_wrap_timeval(gpr_inf_past(GPR_CLOCK_REALTIME) TSRMLS_CC);
   RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
 }
 
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index c4d5679..9f0b02b 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -62,7 +62,7 @@
         Channel $channel,
         $method,
         $deserialize,
-        $options = []
+        array $options = []
     ) {
         if (array_key_exists('timeout', $options) &&
             is_numeric($timeout = $options['timeout'])
@@ -89,7 +89,7 @@
     }
 
     /**
-     * @return mixed The metadata sent by the server.
+     * @return mixed The metadata sent by the server
      */
     public function getMetadata()
     {
@@ -97,7 +97,7 @@
     }
 
     /**
-     * @return mixed The trailing metadata sent by the server.
+     * @return mixed The trailing metadata sent by the server
      */
     public function getTrailingMetadata()
     {
@@ -105,7 +105,7 @@
     }
 
     /**
-     * @return string The URI of the endpoint.
+     * @return string The URI of the endpoint
      */
     public function getPeer()
     {
@@ -167,8 +167,7 @@
     /**
      * Set the CallCredentials for the underlying Call.
      *
-     * @param CallCredentials $call_credentials The CallCredentials
-     *                                          object
+     * @param CallCredentials $call_credentials The CallCredentials object
      */
     public function setCallCredentials($call_credentials)
     {
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index d0baeae..a9e77b9 100644
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -48,14 +48,14 @@
     private $update_metadata;
 
     /**
-     * @param $hostname string
-     * @param $opts array
+     * @param string  $hostname
+     * @param array   $opts
      *  - 'update_metadata': (optional) a callback function which takes in a
      * metadata array, and returns an updated metadata array
      *  - 'grpc.primary_user_agent': (optional) a user-agent string
-     * @param $channel Channel An already created Channel object
+     * @param Channel $channel An already created Channel object (optional)
      */
-    public function __construct($hostname, $opts, $channel = null)
+    public function __construct($hostname, $opts, Channel $channel = null)
     {
         $ssl_roots = file_get_contents(
             dirname(__FILE__).'/../../../../etc/roots.pem');
@@ -98,7 +98,7 @@
     }
 
     /**
-     * @return string The URI of the endpoint.
+     * @return string The URI of the endpoint
      */
     public function getTarget()
     {
@@ -106,7 +106,7 @@
     }
 
     /**
-     * @param $try_to_connect bool
+     * @param bool $try_to_connect (optional)
      *
      * @return int The grpc connectivity state
      */
@@ -145,6 +145,12 @@
         return $this->_checkConnectivityState($new_state);
     }
 
+    /**
+     * @param $new_state Connect state
+     *
+     * @return bool true if state is CHANNEL_READY
+     * @throw Exception if state is CHANNEL_FATAL_FAILURE
+     */
     private function _checkConnectivityState($new_state)
     {
         if ($new_state == \Grpc\CHANNEL_READY) {
@@ -167,6 +173,10 @@
 
     /**
      * constructs the auth uri for the jwt.
+     *
+     * @param string $method The method string
+     *
+     * @return string The URL string
      */
     private function _get_jwt_aud_uri($method)
     {
@@ -191,7 +201,7 @@
      *
      * @param array $metadata The metadata map
      *
-     * @return $metadata Validated and key-normalized metadata map
+     * @return array $metadata Validated and key-normalized metadata map
      * @throw InvalidArgumentException if key contains invalid characters
      */
     private function _validate_and_normalize_metadata($metadata)
@@ -220,14 +230,16 @@
      * @param mixed    $argument    The argument to the method
      * @param callable $deserialize A function that deserializes the response
      * @param array    $metadata    A metadata map to send to the server
+     *                              (optional)
+     * @param array    $options     An array of options (optional)
      *
      * @return SimpleSurfaceActiveCall The active call object
      */
     public function _simpleRequest($method,
                                    $argument,
                                    $deserialize,
-                                   $metadata = [],
-                                   $options = [])
+                                   array $metadata = [],
+                                   array $options = [])
     {
         $call = new UnaryCall($this->channel,
                               $method,
@@ -251,17 +263,17 @@
      * output.
      *
      * @param string   $method      The name of the method to call
-     * @param array    $arguments   An array or Traversable of arguments to stream to the
-     *                              server
      * @param callable $deserialize A function that deserializes the response
      * @param array    $metadata    A metadata map to send to the server
+     *                              (optional)
+     * @param array    $options     An array of options (optional)
      *
      * @return ClientStreamingSurfaceActiveCall The active call object
      */
     public function _clientStreamRequest($method,
-                                         callable $deserialize,
-                                         $metadata = [],
-                                         $options = [])
+                                         $deserialize,
+                                         array $metadata = [],
+                                         array $options = [])
     {
         $call = new ClientStreamingCall($this->channel,
                                         $method,
@@ -281,21 +293,23 @@
     }
 
     /**
-     * Call a remote method that takes a single argument and returns a stream of
-     * responses.
+     * Call a remote method that takes a single argument and returns a stream
+     * of responses.
      *
      * @param string   $method      The name of the method to call
      * @param mixed    $argument    The argument to the method
      * @param callable $deserialize A function that deserializes the responses
      * @param array    $metadata    A metadata map to send to the server
+     *                              (optional)
+     * @param array    $options     An array of options (optional)
      *
      * @return ServerStreamingSurfaceActiveCall The active call object
      */
     public function _serverStreamRequest($method,
                                          $argument,
-                                         callable $deserialize,
-                                         $metadata = [],
-                                         $options = [])
+                                         $deserialize,
+                                         array $metadata = [],
+                                         array $options = [])
     {
         $call = new ServerStreamingCall($this->channel,
                                         $method,
@@ -320,13 +334,15 @@
      * @param string   $method      The name of the method to call
      * @param callable $deserialize A function that deserializes the responses
      * @param array    $metadata    A metadata map to send to the server
+     *                              (optional)
+     * @param array    $options     An array of options (optional)
      *
      * @return BidiStreamingSurfaceActiveCall The active call object
      */
     public function _bidiRequest($method,
-                                 callable $deserialize,
-                                 $metadata = [],
-                                 $options = [])
+                                 $deserialize,
+                                 array $metadata = [],
+                                 array $options = [])
     {
         $call = new BidiStreamingCall($this->channel,
                                       $method,
diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index f0e1e81..b03bbd2 100644
--- a/src/php/lib/Grpc/BidiStreamingCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -35,8 +35,8 @@
 namespace Grpc;
 
 /**
- * Represents an active call that allows for sending and recieving messages in
- * streams in any order.
+ * Represents an active call that allows for sending and recieving messages
+ * in streams in any order.
  */
 class BidiStreamingCall extends AbstractCall
 {
@@ -44,6 +44,7 @@
      * Start the call.
      *
      * @param array $metadata Metadata to send with the call, if applicable
+     *                        (optional)
      */
     public function start(array $metadata = [])
     {
@@ -76,10 +77,10 @@
      * writesDone is called.
      *
      * @param ByteBuffer $data    The data to write
-     * @param array      $options an array of options, possible keys:
-     *                            'flags' => a number
+     * @param array      $options An array of options, possible keys:
+     *                            'flags' => a number (optional)
      */
-    public function write($data, $options = [])
+    public function write($data, array $options = [])
     {
         $message_array = ['message' => $this->serializeMessage($data)];
         if (array_key_exists('flags', $options)) {
@@ -103,8 +104,8 @@
     /**
      * Wait for the server to send the status, and return it.
      *
-     * @return \stdClass The status object, with integer $code, string $details,
-     *                   and array $metadata members
+     * @return \stdClass The status object, with integer $code, string
+     *                   $details, and array $metadata members
      */
     public function getStatus()
     {
diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index 20db809..c542f08 100644
--- a/src/php/lib/Grpc/ClientStreamingCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -35,8 +35,8 @@
 namespace Grpc;
 
 /**
- * Represents an active call that sends a stream of messages and then gets a
- * single response.
+ * Represents an active call that sends a stream of messages and then gets
+ * a single response.
  */
 class ClientStreamingCall extends AbstractCall
 {
@@ -44,8 +44,9 @@
      * Start the call.
      *
      * @param array $metadata Metadata to send with the call, if applicable
+     *                        (optional)
      */
-    public function start($metadata = [])
+    public function start(array $metadata = [])
     {
         $this->call->startBatch([
             OP_SEND_INITIAL_METADATA => $metadata,
@@ -57,8 +58,8 @@
      * wait is called.
      *
      * @param ByteBuffer $data    The data to write
-     * @param array      $options an array of options, possible keys:
-     *                            'flags' => a number
+     * @param array      $options An array of options, possible keys:
+     *                            'flags' => a number (optional)
      */
     public function write($data, array $options = [])
     {
diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index 5aeeafa..406512b 100644
--- a/src/php/lib/Grpc/ServerStreamingCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -35,8 +35,8 @@
 namespace Grpc;
 
 /**
- * Represents an active call that sends a single message and then gets a stream
- * of responses.
+ * Represents an active call that sends a single message and then gets a
+ * stream of responses.
  */
 class ServerStreamingCall extends AbstractCall
 {
@@ -45,10 +45,11 @@
      *
      * @param mixed $data     The data to send
      * @param array $metadata Metadata to send with the call, if applicable
-     * @param array $options  an array of options, possible keys:
-     *                        'flags' => a number
+     *                        (optional)
+     * @param array $options  An array of options, possible keys:
+     *                        'flags' => a number (optional)
      */
-    public function start($data, $metadata = [], $options = [])
+    public function start($data, array $metadata = [], array $options = [])
     {
         $message_array = ['message' => $this->serializeMessage($data)];
         if (array_key_exists('flags', $options)) {
@@ -82,8 +83,8 @@
     /**
      * Wait for the server to send the status, and return it.
      *
-     * @return \stdClass The status object, with integer $code, string $details,
-     *                   and array $metadata members
+     * @return \stdClass The status object, with integer $code, string
+     *                   $details, and array $metadata members
      */
     public function getStatus()
     {
diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php
index e8eb648..3c1cb15 100644
--- a/src/php/lib/Grpc/UnaryCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -35,8 +35,8 @@
 namespace Grpc;
 
 /**
- * Represents an active call that sends a single message and then gets a single
- * response.
+ * Represents an active call that sends a single message and then gets a
+ * single response.
  */
 class UnaryCall extends AbstractCall
 {
@@ -45,10 +45,11 @@
      *
      * @param mixed $data     The data to send
      * @param array $metadata Metadata to send with the call, if applicable
-     * @param array $options  an array of options, possible keys:
-     *                        'flags' => a number
+     *                        (optional)
+     * @param array $options  An array of options, possible keys:
+     *                        'flags' => a number (optional)
      */
-    public function start($data, $metadata = [], $options = [])
+    public function start($data, array $metadata = [], array $options = [])
     {
         $message_array = ['message' => $this->serializeMessage($data)];
         if (isset($options['flags'])) {
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index d201915..2acf561 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -451,11 +451,22 @@
 
     $streaming_request = new grpc\testing\StreamingOutputCallRequest();
     $streaming_request->setPayload($payload);
+    $response_parameters = new grpc\testing\ResponseParameters();
+    $response_parameters->setSize($response_len);
+    $streaming_request->getResponseParameters()[] = $response_parameters;
     $streaming_call->write($streaming_request);
     $streaming_call->writesDone();
+    $result = $streaming_call->read();
 
     hardAssertIfStatusOk($streaming_call->getStatus());
 
+    $streaming_initial_metadata = $streaming_call->getMetadata();
+    hardAssert(array_key_exists($ECHO_INITIAL_KEY, $streaming_initial_metadata),
+               'Initial metadata does not contain expected key');
+    hardAssert(
+        $streaming_initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
+        'Incorrect initial metadata value');
+
     $streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
     hardAssert(array_key_exists($ECHO_TRAILING_KEY,
                                 $streaming_trailing_metadata),
diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD
new file mode 100644
index 0000000..f9f9cbc
--- /dev/null
+++ b/src/proto/grpc/testing/BUILD
@@ -0,0 +1,63 @@
+
+package(default_visibility = ["//visibility:public"])
+
+load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
+
+grpc_proto_library(
+    name = "compiler_test_proto",
+    srcs = ["compiler_test.proto"],
+)
+
+grpc_proto_library(
+    name = "control_proto",
+    srcs = ["control.proto"],
+    deps = ["payloads_proto", "stats_proto"],
+)
+
+grpc_proto_library(
+    name = "echo_messages_proto",
+    srcs = ["echo_messages.proto"],
+)
+
+grpc_proto_library(
+    name = "echo_proto",
+    srcs = ["echo.proto"],
+    deps = ["echo_messages_proto"],
+)
+
+grpc_proto_library(
+    name = "empty_proto",
+    srcs = ["empty.proto"],
+)
+
+grpc_proto_library(
+    name = "messages_proto",
+    srcs = ["messages.proto"],
+)
+
+grpc_proto_library(
+    name = "metrics_proto",
+    srcs = ["metrics.proto"],
+)
+
+grpc_proto_library(
+    name = "payloads_proto",
+    srcs = ["payloads.proto"],
+)
+
+grpc_proto_library(
+    name = "services_proto",
+    srcs = ["services.proto"],
+    deps = ["control_proto", "messages_proto"],
+)
+
+grpc_proto_library(
+    name = "stats_proto",
+    srcs = ["stats.proto"],
+)
+
+grpc_proto_library(
+    name = "test_proto",
+    srcs = ["test.proto"],
+    deps = ["empty_proto", "messages_proto"],
+)
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index be387cf..529313c 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -78,6 +78,14 @@
   string server_host_override = 2;
 }
 
+message ChannelArg {
+  string name = 1;
+  oneof value {
+    string str_value = 2;
+    int32 int_value = 3;
+  }
+}
+
 message ClientConfig {
   // List of targets to connect to. At least one target needs to be specified.
   repeated string server_targets = 1;
@@ -103,6 +111,8 @@
 
   // If we use an OTHER_CLIENT client_type, this string gives more detail
   string other_client_api = 15;
+
+  repeated ChannelArg channel_args = 16;
 }
 
 message ClientStatus { ClientStats stats = 1; }
diff --git a/src/proto/grpc/testing/duplicate/BUILD b/src/proto/grpc/testing/duplicate/BUILD
new file mode 100644
index 0000000..255e699
--- /dev/null
+++ b/src/proto/grpc/testing/duplicate/BUILD
@@ -0,0 +1,10 @@
+
+package(default_visibility = ["//visibility:public"])
+
+load("//bazel:grpc_build_system.bzl", "grpc_proto_library")
+
+grpc_proto_library(
+    name = "echo_duplicate_proto",
+    srcs = ["echo_duplicate.proto"],
+    deps = ["//src/proto/grpc/testing:echo_messages_proto"],
+)
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index ea3b6f3..701c6af 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -62,6 +62,7 @@
 napoleon_include_special_with_doc = True
 
 html_theme = 'sphinx_rtd_theme'
+copyright = "2016, The gRPC Authors"
 """
 
 API_GLOSSARY = """
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index cfad7de..e3c1015 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -31,6 +31,7 @@
 
 import abc
 import enum
+import sys
 
 import six
 
@@ -767,8 +768,8 @@
     gRPC runtime to determine the status code of the RPC.
 
     Args:
-      code: The integer status code of the RPC to be transmitted to the
-        invocation side of the RPC.
+      code: A StatusCode value to be transmitted to the invocation side of the
+        RPC as the status code of the RPC.
     """
     raise NotImplementedError()
 
@@ -780,8 +781,8 @@
     details to transmit.
 
     Args:
-      details: The details string of the RPC to be transmitted to
-        the invocation side of the RPC.
+      details: A string to be transmitted to the invocation side of the RPC as
+        the status details of the RPC.
     """
     raise NotImplementedError()
 
@@ -925,21 +926,6 @@
     raise NotImplementedError()
 
   @abc.abstractmethod
-  def add_shutdown_handler(self, shutdown_handler):
-    """Adds a handler to be called on server shutdown.
-
-    Shutdown handlers are run on server stop() or in the event that a running
-    server is destroyed unexpectedly.  The handlers are run in series before
-    the stop grace period.
-
-    Args:
-      shutdown_handler:  A function taking a single arg, a time in seconds
-      within which the handler should complete.  None indicates the handler can
-      run for any duration.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
   def start(self):
     """Starts this Server's service of RPCs.
 
@@ -949,7 +935,7 @@
     raise NotImplementedError()
 
   @abc.abstractmethod
-  def stop(self, grace, shutdown_handler_grace=None):
+  def stop(self, grace):
     """Stops this Server's service of RPCs.
 
     All calls to this method immediately stop service of new RPCs. When existing
@@ -972,8 +958,6 @@
         aborted by this Server's stopping. If None, all RPCs will be aborted
         immediately and this method will block until this Server is completely
         stopped.
-      shutdown_handler_grace:  A duration of time in seconds or None.  This
-        value is passed to all shutdown handlers.
 
     Returns:
       A threading.Event that will be set when this Server has completely
@@ -1268,8 +1252,7 @@
                           credentials._credentials)
 
 
-def server(thread_pool, handlers=None, options=None, exit_grace=None,
-           exit_shutdown_handler_grace=None):
+def server(thread_pool, handlers=None, options=None):
   """Creates a Server with which RPCs can be serviced.
 
   Args:
@@ -1282,19 +1265,13 @@
       returned Server is started.
     options: A sequence of string-value pairs according to which to configure
       the created server.
-    exit_grace:  The grace period to use when terminating
-      running servers at interpreter exit.  None indicates unspecified.
-    exit_shutdown_handler_grace:  The shutdown handler grace to use when
-      terminating running servers at interpreter exit.  None indicates
-      unspecified.
 
   Returns:
     A Server with which RPCs can be serviced.
   """
   from grpc import _server
   return _server.Server(thread_pool, () if handlers is None else handlers,
-                        () if options is None else options, exit_grace,
-                        exit_shutdown_handler_grace)
+                        () if options is None else options)
 
 
 ###################################  __all__  #################################
@@ -1342,3 +1319,24 @@
     'secure_channel',
     'server',
 )
+
+
+############################### Extension Shims ################################
+
+
+# Here to maintain backwards compatibility; avoid using these in new code!
+try:
+  import grpc_tools
+  sys.modules.update({'grpc.tools': grpc_tools})
+except ImportError:
+  pass
+try:
+  import grpc_health
+  sys.modules.update({'grpc.health': grpc_health})
+except ImportError:
+  pass
+try:
+  import grpc_reflection
+  sys.modules.update({'grpc.reflection': grpc_reflection})
+except ImportError:
+  pass
diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py
index 53a2672..e8c6a99 100644
--- a/src/python/grpcio/grpc/_channel.py
+++ b/src/python/grpcio/grpc/_channel.py
@@ -32,12 +32,13 @@
 import sys
 import threading
 import time
+import logging
 
 import grpc
 from grpc import _common
 from grpc import _grpcio_metadata
-from grpc.framework.foundation import callable_util
 from grpc._cython import cygrpc
+from grpc.framework.foundation import callable_util
 
 _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
 
@@ -99,6 +100,22 @@
     else:
       condition.wait(timeout=remaining)
 
+_INTERNAL_CALL_ERROR_MESSAGE_FORMAT = (
+    'Internal gRPC call error %d. ' +
+    'Please report to https://github.com/grpc/grpc/issues')
+
+def _check_call_error(call_error, metadata):
+  if call_error == cygrpc.CallError.invalid_metadata:
+    raise ValueError('metadata was invalid: %s' % metadata)
+  elif call_error != cygrpc.CallError.ok:
+    raise ValueError(_INTERNAL_CALL_ERROR_MESSAGE_FORMAT % call_error)
+
+def _call_error_set_RPCstate(state, call_error, metadata):
+  if call_error == cygrpc.CallError.invalid_metadata:
+    _abort(state, grpc.StatusCode.INTERNAL, 'metadata was invalid: %s' % metadata)
+  else:
+    _abort(state, grpc.StatusCode.INTERNAL, 
+        _INTERNAL_CALL_ERROR_MESSAGE_FORMAT % call_error)
 
 class _RPCState(object):
 
@@ -181,7 +198,16 @@
   event_handler = _event_handler(state, call, None)
 
   def consume_request_iterator():
-    for request in request_iterator:
+    while True:
+      try:
+        request = next(request_iterator)
+      except StopIteration:
+        break
+      except Exception as e:
+        logging.exception("Exception iterating requests!")
+        call.cancel()
+        _abort(state, grpc.StatusCode.UNKNOWN, "Exception iterating requests!")
+        return
       serialized_request = _common.serialize(request, request_serializer)
       with state.condition:
         if state.code is None and not state.cancelled:
@@ -358,7 +384,7 @@
       if self._state.callbacks is None:
         return False
       else:
-        self._state.callbacks.append(lambda: callback())
+        self._state.callbacks.append(callback)
         return True
 
   def initial_metadata(self):
@@ -435,10 +461,10 @@
 class _UnaryUnaryMultiCallable(grpc.UnaryUnaryMultiCallable):
 
   def __init__(
-      self, channel, create_managed_call, method, request_serializer,
+      self, channel, managed_call, method, request_serializer,
       response_deserializer):
     self._channel = channel
-    self._create_managed_call = create_managed_call
+    self._managed_call = managed_call
     self._method = method
     self._request_serializer = request_serializer
     self._response_deserializer = response_deserializer
@@ -472,7 +498,8 @@
           None, 0, completion_queue, self._method, None, deadline_timespec)
       if credentials is not None:
         call.set_credentials(credentials._credentials)
-      call.start_client_batch(cygrpc.Operations(operations), None)
+      call_error = call.start_client_batch(cygrpc.Operations(operations), None)
+      _check_call_error(call_error, metadata)
       _handle_event(completion_queue.poll(), state, self._response_deserializer)
       return state, deadline
 
@@ -490,23 +517,28 @@
     if rendezvous:
       return rendezvous
     else:
-      call = self._create_managed_call(
+      call, drive_call = self._managed_call(
           None, 0, self._method, None, deadline_timespec)
       if credentials is not None:
         call.set_credentials(credentials._credentials)
       event_handler = _event_handler(state, call, self._response_deserializer)
       with state.condition:
-        call.start_client_batch(cygrpc.Operations(operations), event_handler)
+        call_error = call.start_client_batch(cygrpc.Operations(operations),
+            event_handler)
+        if call_error != cygrpc.CallError.ok:
+          _call_error_set_RPCstate(state, call_error, metadata)
+          return _Rendezvous(state, None, None, deadline)
+        drive_call()
       return _Rendezvous(state, call, self._response_deserializer, deadline)
 
 
 class _UnaryStreamMultiCallable(grpc.UnaryStreamMultiCallable):
 
   def __init__(
-      self, channel, create_managed_call, method, request_serializer,
+      self, channel, managed_call, method, request_serializer,
       response_deserializer):
     self._channel = channel
-    self._create_managed_call = create_managed_call
+    self._managed_call = managed_call
     self._method = method
     self._request_serializer = request_serializer
     self._response_deserializer = response_deserializer
@@ -518,7 +550,7 @@
       raise rendezvous
     else:
       state = _RPCState(_UNARY_STREAM_INITIAL_DUE, None, None, None, None)
-      call = self._create_managed_call(
+      call, drive_call = self._managed_call(
           None, 0, self._method, None, deadline_timespec)
       if credentials is not None:
         call.set_credentials(credentials._credentials)
@@ -535,17 +567,22 @@
             cygrpc.operation_send_close_from_client(_EMPTY_FLAGS),
             cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
         )
-        call.start_client_batch(cygrpc.Operations(operations), event_handler)
+        call_error = call.start_client_batch(cygrpc.Operations(operations),
+            event_handler)
+        if call_error != cygrpc.CallError.ok:
+          _call_error_set_RPCstate(state, call_error, metadata)
+          return _Rendezvous(state, None, None, deadline)
+        drive_call()
       return _Rendezvous(state, call, self._response_deserializer, deadline)
 
 
 class _StreamUnaryMultiCallable(grpc.StreamUnaryMultiCallable):
 
   def __init__(
-      self, channel, create_managed_call, method, request_serializer,
+      self, channel, managed_call, method, request_serializer,
       response_deserializer):
     self._channel = channel
-    self._create_managed_call = create_managed_call
+    self._managed_call = managed_call
     self._method = method
     self._request_serializer = request_serializer
     self._response_deserializer = response_deserializer
@@ -569,7 +606,8 @@
           cygrpc.operation_receive_message(_EMPTY_FLAGS),
           cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
       )
-      call.start_client_batch(cygrpc.Operations(operations), None)
+      call_error = call.start_client_batch(cygrpc.Operations(operations), None)
+      _check_call_error(call_error, metadata)
       _consume_request_iterator(
           request_iterator, state, call, self._request_serializer)
     while True:
@@ -597,7 +635,7 @@
       self, request_iterator, timeout=None, metadata=None, credentials=None):
     deadline, deadline_timespec = _deadline(timeout)
     state = _RPCState(_STREAM_UNARY_INITIAL_DUE, None, None, None, None)
-    call = self._create_managed_call(
+    call, drive_call = self._managed_call(
         None, 0, self._method, None, deadline_timespec)
     if credentials is not None:
       call.set_credentials(credentials._credentials)
@@ -613,7 +651,12 @@
           cygrpc.operation_receive_message(_EMPTY_FLAGS),
           cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
       )
-      call.start_client_batch(cygrpc.Operations(operations), event_handler)
+      call_error = call.start_client_batch(cygrpc.Operations(operations),
+          event_handler)
+      if call_error != cygrpc.CallError.ok:
+        _call_error_set_RPCstate(state, call_error, metadata)
+        return _Rendezvous(state, None, None, deadline)
+      drive_call()
       _consume_request_iterator(
           request_iterator, state, call, self._request_serializer)
     return _Rendezvous(state, call, self._response_deserializer, deadline)
@@ -622,10 +665,10 @@
 class _StreamStreamMultiCallable(grpc.StreamStreamMultiCallable):
 
   def __init__(
-      self, channel, create_managed_call, method, request_serializer,
+      self, channel, managed_call, method, request_serializer,
       response_deserializer):
     self._channel = channel
-    self._create_managed_call = create_managed_call
+    self._managed_call = managed_call
     self._method = method
     self._request_serializer = request_serializer
     self._response_deserializer = response_deserializer
@@ -634,7 +677,7 @@
       self, request_iterator, timeout=None, metadata=None, credentials=None):
     deadline, deadline_timespec = _deadline(timeout)
     state = _RPCState(_STREAM_STREAM_INITIAL_DUE, None, None, None, None)
-    call = self._create_managed_call(
+    call, drive_call = self._managed_call(
         None, 0, self._method, None, deadline_timespec)
     if credentials is not None:
       call.set_credentials(credentials._credentials)
@@ -649,7 +692,12 @@
               _common.cygrpc_metadata(metadata), _EMPTY_FLAGS),
           cygrpc.operation_receive_status_on_client(_EMPTY_FLAGS),
       )
-      call.start_client_batch(cygrpc.Operations(operations), event_handler)
+      call_error = call.start_client_batch(cygrpc.Operations(operations),
+          event_handler)
+      if call_error != cygrpc.CallError.ok:
+        _call_error_set_RPCstate(state, call_error, metadata)
+        return _Rendezvous(state, None, None, deadline)
+      drive_call()
       _consume_request_iterator(
           request_iterator, state, call, self._request_serializer)
     return _Rendezvous(state, call, self._response_deserializer, deadline)
@@ -687,16 +735,13 @@
   channel_spin_thread.start()
 
 
-def _create_channel_managed_call(state):
-  def create_channel_managed_call(parent, flags, method, host, deadline):
-    """Creates a managed cygrpc.Call.
+def _channel_managed_call_management(state):
+  def create(parent, flags, method, host, deadline):
+    """Creates a managed cygrpc.Call and a function to call to drive it.
 
-    Callers of this function must conduct at least one operation on the returned
-    call. The tags associated with operations conducted on the returned call
-    must be no-argument callables that return None to indicate that this channel
-    should continue polling for events associated with the call and return the
-    call itself to indicate that no more events associated with the call will be
-    generated.
+    If operations are successfully added to the returned cygrpc.Call, the
+    returned function must be called. If operations are not successfully added
+    to the returned cygrpc.Call, the returned function must not be called.
 
     Args:
       parent: A cygrpc.Call to be used as the parent of the created call.
@@ -706,18 +751,22 @@
       deadline: A cygrpc.Timespec to be the deadline of the created call.
 
     Returns:
-      A cygrpc.Call with which to conduct an RPC.
+      A cygrpc.Call with which to conduct an RPC and a function to call if
+        operations are successfully started on the call.
     """
-    with state.lock:
-      call = state.channel.create_call(
-          parent, flags, state.completion_queue, method, host, deadline)
-      if state.managed_calls is None:
-        state.managed_calls = set((call,))
-        _run_channel_spin_thread(state)
-      else:
-        state.managed_calls.add(call)
-      return call
-  return create_channel_managed_call
+    call = state.channel.create_call(
+        parent, flags, state.completion_queue, method, host, deadline)
+
+    def drive():
+      with state.lock:
+        if state.managed_calls is None:
+          state.managed_calls = set((call,))
+          _run_channel_spin_thread(state)
+        else:
+          state.managed_calls.add(call)
+
+    return call, drive
+  return create
 
 
 class _ChannelConnectivityState(object):
@@ -847,6 +896,7 @@
 
 
 class Channel(grpc.Channel):
+  """A cygrpc.Channel-backed implementation of grpc.Channel."""
 
   def __init__(self, target, options, credentials):
     """Constructor.
@@ -871,25 +921,25 @@
   def unary_unary(
       self, method, request_serializer=None, response_deserializer=None):
     return _UnaryUnaryMultiCallable(
-        self._channel, _create_channel_managed_call(self._call_state),
+        self._channel, _channel_managed_call_management(self._call_state),
         _common.encode(method), request_serializer, response_deserializer)
 
   def unary_stream(
       self, method, request_serializer=None, response_deserializer=None):
     return _UnaryStreamMultiCallable(
-        self._channel, _create_channel_managed_call(self._call_state),
+        self._channel, _channel_managed_call_management(self._call_state),
         _common.encode(method), request_serializer, response_deserializer)
 
   def stream_unary(
       self, method, request_serializer=None, response_deserializer=None):
     return _StreamUnaryMultiCallable(
-        self._channel, _create_channel_managed_call(self._call_state),
+        self._channel, _channel_managed_call_management(self._call_state),
         _common.encode(method), request_serializer, response_deserializer)
 
   def stream_stream(
       self, method, request_serializer=None, response_deserializer=None):
     return _StreamStreamMultiCallable(
-        self._channel, _create_channel_managed_call(self._call_state),
+        self._channel, _channel_managed_call_management(self._call_state),
         _common.encode(method), request_serializer, response_deserializer)
 
   def __del__(self):
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index d83a2e6..5223712 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -60,8 +60,7 @@
 _EMPTY_FLAGS = 0
 _EMPTY_METADATA = cygrpc.Metadata(())
 
-_DEFAULT_EXIT_GRACE = 1.0
-_DEFAULT_EXIT_SHUTDOWN_HANDLER_GRACE = 5.0
+_UNEXPECTED_EXIT_SERVER_GRACE = 1.0
 
 
 def _serialized_request(request_event):
@@ -596,18 +595,14 @@
 
 class _ServerState(object):
 
-  def __init__(self, completion_queue, server, generic_handlers, thread_pool,
-               exit_grace, exit_shutdown_handler_grace):
+  def __init__(self, completion_queue, server, generic_handlers, thread_pool):
     self.lock = threading.Lock()
     self.completion_queue = completion_queue
     self.server = server
     self.generic_handlers = list(generic_handlers)
     self.thread_pool = thread_pool
-    self.exit_grace = exit_grace
-    self.exit_shutdown_handler_grace = exit_shutdown_handler_grace
     self.stage = _ServerStage.STOPPED
     self.shutdown_events = None
-    self.shutdown_handlers = []
 
     # TODO(https://github.com/grpc/grpc/issues/6597): eliminate these fields.
     self.rpc_states = set()
@@ -677,45 +672,41 @@
             return
 
 
-def _stop(state, grace, shutdown_handler_grace):
-  shutdown_event = threading.Event()
-
-  def cancel_all_calls_after_grace():
-    with state.lock:
-      if state.stage is _ServerStage.STOPPED:
-        shutdown_event.set()
-        return
-      elif state.stage is _ServerStage.STARTED:
-        do_shutdown = True
-        state.stage = _ServerStage.GRACE
-        state.shutdown_events = []
-      else:
-        do_shutdown = False
-      state.shutdown_events.append(shutdown_event)
-
-    if do_shutdown:
-      # Run Shutdown Handlers without the lock
-      for handler in state.shutdown_handlers:
-        handler(shutdown_handler_grace)
-      with state.lock:
+def _stop(state, grace):
+  with state.lock:
+    if state.stage is _ServerStage.STOPPED:
+      shutdown_event = threading.Event()
+      shutdown_event.set()
+      return shutdown_event
+    else:
+      if state.stage is _ServerStage.STARTED:
         state.server.shutdown(state.completion_queue, _SHUTDOWN_TAG)
         state.stage = _ServerStage.GRACE
+        state.shutdown_events = []
         state.due.add(_SHUTDOWN_TAG)
-
-    if not shutdown_event.wait(timeout=grace):
-      with state.lock:
+      shutdown_event = threading.Event()
+      state.shutdown_events.append(shutdown_event)
+      if grace is None:
         state.server.cancel_all_calls()
         # TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
         for rpc_state in state.rpc_states:
           with rpc_state.condition:
             rpc_state.client = _CANCELLED
             rpc_state.condition.notify_all()
-
-  if grace is None:
-    cancel_all_calls_after_grace()
-  else:
-    threading.Thread(target=cancel_all_calls_after_grace).start()
-
+      else:
+        def cancel_all_calls_after_grace():
+          shutdown_event.wait(timeout=grace)
+          with state.lock:
+            state.server.cancel_all_calls()
+            # TODO(https://github.com/grpc/grpc/issues/6597): delete this loop.
+            for rpc_state in state.rpc_states:
+              with rpc_state.condition:
+                rpc_state.client = _CANCELLED
+                rpc_state.condition.notify_all()
+        thread = threading.Thread(target=cancel_all_calls_after_grace)
+        thread.start()
+        return shutdown_event
+  shutdown_event.wait()
   return shutdown_event
 
 
@@ -725,12 +716,12 @@
       raise ValueError('Cannot start already-started server!')
     state.server.start()
     state.stage = _ServerStage.STARTED
-    _request_call(state)
+    _request_call(state)    
     def cleanup_server(timeout):
       if timeout is None:
-        _stop(state, state.exit_grace, state.exit_shutdown_handler_grace).wait()
+        _stop(state, _UNEXPECTED_EXIT_SERVER_GRACE).wait()
       else:
-        _stop(state, timeout, 0).wait()
+        _stop(state, timeout).wait()
 
     thread = _common.CleanupThread(
         cleanup_server, target=_serve, args=(state,))
@@ -738,16 +729,12 @@
 
 class Server(grpc.Server):
 
-  def __init__(self, thread_pool, generic_handlers, options, exit_grace,
-               exit_shutdown_handler_grace):
+  def __init__(self, thread_pool, generic_handlers, options):
     completion_queue = cygrpc.CompletionQueue()
     server = cygrpc.Server(_common.channel_args(options))
     server.register_completion_queue(completion_queue)
     self._state = _ServerState(
-        completion_queue, server, generic_handlers, thread_pool,
-        _DEFAULT_EXIT_GRACE if exit_grace is None else exit_grace,
-        _DEFAULT_EXIT_SHUTDOWN_HANDLER_GRACE if exit_shutdown_handler_grace
-        is None else exit_shutdown_handler_grace)
+        completion_queue, server, generic_handlers, thread_pool)
 
   def add_generic_rpc_handlers(self, generic_rpc_handlers):
     _add_generic_handlers(self._state, generic_rpc_handlers)
@@ -758,14 +745,11 @@
   def add_secure_port(self, address, server_credentials):
     return _add_secure_port(self._state, _common.encode(address), server_credentials)
 
-  def add_shutdown_handler(self, handler):
-    self._state.shutdown_handlers.append(handler)
-
   def start(self):
     _start(self._state)
 
-  def stop(self, grace, shutdown_handler_grace=None):
-    return _stop(self._state, grace, shutdown_handler_grace)
+  def stop(self, grace):
+    return _stop(self._state, grace)
 
   def __del__(self):
-    _stop(self._state, None, None)
+    _stop(self._state, None)
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index d43f93b..e27e9e1 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -82,6 +82,8 @@
   'src/core/lib/channel/connected_channel.c',
   'src/core/lib/channel/deadline_filter.c',
   'src/core/lib/channel/handshaker.c',
+  'src/core/lib/channel/handshaker_factory.c',
+  'src/core/lib/channel/handshaker_registry.c',
   'src/core/lib/channel/http_client_filter.c',
   'src/core/lib/channel/http_server_filter.c',
   'src/core/lib/channel/message_size_filter.c',
diff --git a/src/python/grpcio/support.py b/src/python/grpcio/support.py
index f363f5f..b226e69 100644
--- a/src/python/grpcio/support.py
+++ b/src/python/grpcio/support.py
@@ -100,9 +100,15 @@
             .format(source)
           )
 
+def diagnose_attribute_error(build_ext, error):
+  if any('_needs_stub' in arg for arg in error.args):
+    raise commands.CommandError(
+        "We expect a missing `_needs_stub` attribute from older versions of "
+        "setuptools. Consider upgrading setuptools.")
 
 _ERROR_DIAGNOSES = {
-    errors.CompileError: diagnose_compile_error
+    errors.CompileError: diagnose_compile_error,
+    AttributeError: diagnose_attribute_error
 }
 
 def diagnose_build_ext_error(build_ext, error, formatted):
diff --git a/src/python/grpcio_health_checking/MANIFEST.in b/src/python/grpcio_health_checking/MANIFEST.in
index 7407f64..5255e4c 100644
--- a/src/python/grpcio_health_checking/MANIFEST.in
+++ b/src/python/grpcio_health_checking/MANIFEST.in
@@ -1,4 +1,4 @@
 include grpc_version.py
 include health_commands.py
-graft grpc
+graft grpc_health
 global-exclude *.pyc
diff --git a/src/python/grpcio_health_checking/grpc/health/__init__.py b/src/python/grpcio_health_checking/grpc_health/__init__.py
similarity index 100%
rename from src/python/grpcio_health_checking/grpc/health/__init__.py
rename to src/python/grpcio_health_checking/grpc_health/__init__.py
diff --git a/src/python/grpcio_health_checking/grpc/health/v1/__init__.py b/src/python/grpcio_health_checking/grpc_health/v1/__init__.py
similarity index 100%
rename from src/python/grpcio_health_checking/grpc/health/v1/__init__.py
rename to src/python/grpcio_health_checking/grpc_health/v1/__init__.py
diff --git a/src/python/grpcio_health_checking/grpc/health/v1/health.py b/src/python/grpcio_health_checking/grpc_health/v1/health.py
similarity index 98%
rename from src/python/grpcio_health_checking/grpc/health/v1/health.py
rename to src/python/grpcio_health_checking/grpc_health/v1/health.py
index 8108ac1..0df679b 100644
--- a/src/python/grpcio_health_checking/grpc/health/v1/health.py
+++ b/src/python/grpcio_health_checking/grpc_health/v1/health.py
@@ -33,7 +33,7 @@
 
 import grpc
 
-from grpc.health.v1 import health_pb2
+from grpc_health.v1 import health_pb2
 
 
 class HealthServicer(health_pb2.HealthServicer):
diff --git a/src/python/grpcio_health_checking/health_commands.py b/src/python/grpcio_health_checking/health_commands.py
index 66df25d..0c420a6 100644
--- a/src/python/grpcio_health_checking/health_commands.py
+++ b/src/python/grpcio_health_checking/health_commands.py
@@ -54,7 +54,7 @@
     if os.path.isfile(HEALTH_PROTO):
       shutil.copyfile(
           HEALTH_PROTO,
-          os.path.join(ROOT_DIR, 'grpc/health/v1/health.proto'))
+          os.path.join(ROOT_DIR, 'grpc_health/v1/health.proto'))
 
 
 class BuildPackageProtos(setuptools.Command):
@@ -74,5 +74,5 @@
     # directory is provided as an 'include' directory. We assume it's the '' key
     # to `self.distribution.package_dir` (and get a key error if it's not
     # there).
-    from grpc.tools import command
+    from grpc_tools import command
     command.build_package_protos(self.distribution.package_dir[''])
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index 8c92ee1..e88f389 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -66,7 +66,6 @@
     license='3-clause BSD',
     package_dir=PACKAGE_DIRECTORIES,
     packages=setuptools.find_packages('.'),
-    namespace_packages=['grpc'],
     install_requires=INSTALL_REQUIRES,
     setup_requires=SETUP_REQUIRES,
     cmdclass=COMMAND_CLASS
diff --git a/src/python/grpcio_reflection/grpc/reflection/__init__.py b/src/python/grpcio_reflection/grpc_reflection/__init__.py
similarity index 100%
rename from src/python/grpcio_reflection/grpc/reflection/__init__.py
rename to src/python/grpcio_reflection/grpc_reflection/__init__.py
diff --git a/src/python/grpcio_reflection/grpc/reflection/v1alpha/__init__.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/__init__.py
similarity index 100%
rename from src/python/grpcio_reflection/grpc/reflection/v1alpha/__init__.py
rename to src/python/grpcio_reflection/grpc_reflection/v1alpha/__init__.py
diff --git a/src/python/grpcio_reflection/grpc/reflection/v1alpha/reflection.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
similarity index 98%
rename from src/python/grpcio_reflection/grpc/reflection/v1alpha/reflection.py
rename to src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
index 3c399b0..bfcbce8 100644
--- a/src/python/grpcio_reflection/grpc/reflection/v1alpha/reflection.py
+++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py
@@ -35,7 +35,7 @@
 from google.protobuf import descriptor_pb2
 from google.protobuf import descriptor_pool
 
-from grpc.reflection.v1alpha import reflection_pb2
+from grpc_reflection.v1alpha import reflection_pb2
 
 _POOL = descriptor_pool.Default()
 
diff --git a/src/python/grpcio_reflection/reflection_commands.py b/src/python/grpcio_reflection/reflection_commands.py
index d189aee..dee5491 100644
--- a/src/python/grpcio_reflection/reflection_commands.py
+++ b/src/python/grpcio_reflection/reflection_commands.py
@@ -54,7 +54,7 @@
     if os.path.isfile(HEALTH_PROTO):
       shutil.copyfile(
           HEALTH_PROTO,
-          os.path.join(ROOT_DIR, 'grpc/reflection/v1alpha/reflection.proto'))
+          os.path.join(ROOT_DIR, 'grpc_reflection/v1alpha/reflection.proto'))
 
 
 class BuildPackageProtos(setuptools.Command):
@@ -74,5 +74,5 @@
     # directory is provided as an 'include' directory. We assume it's the '' key
     # to `self.distribution.package_dir` (and get a key error if it's not
     # there).
-    from grpc.tools import command
+    from grpc_tools import command
     command.build_package_protos(self.distribution.package_dir[''])
diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py
index df95af4..cfc41f4 100644
--- a/src/python/grpcio_reflection/setup.py
+++ b/src/python/grpcio_reflection/setup.py
@@ -66,7 +66,6 @@
     license='3-clause BSD',
     package_dir=PACKAGE_DIRECTORIES,
     packages=setuptools.find_packages('.'),
-    namespace_packages=['grpc'],
     install_requires=INSTALL_REQUIRES,
     setup_requires=SETUP_REQUIRES,
     cmdclass=COMMAND_CLASS
diff --git a/src/python/grpcio_tests/commands.py b/src/python/grpcio_tests/commands.py
index 5ee551c..e822971 100644
--- a/src/python/grpcio_tests/commands.py
+++ b/src/python/grpcio_tests/commands.py
@@ -100,7 +100,7 @@
     pass
 
   def run(self):
-    import grpc.tools.protoc as protoc
+    import grpc_tools.protoc as protoc
 
     include_regex = re.compile(self.include)
     exclude_regex = re.compile(self.exclude) if self.exclude else None
@@ -116,7 +116,7 @@
     # but we currently have name conflicts in src/proto
     for path in paths:
       command = [
-          'grpc.tools.protoc',
+          'grpc_tools.protoc',
           '-I {}'.format(PROTO_STEM),
           '--python_out={}'.format(PROTO_STEM),
           '--grpc_python_out={}'.format(PROTO_STEM),
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index 01d5fa8..375fbd6 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -35,7 +35,7 @@
 
 import setuptools
 
-import grpc.tools.command
+import grpc_tools.command
 
 PY3 = sys.version_info.major == 3
 
@@ -68,7 +68,7 @@
     # Run `preprocess` *before* doing any packaging!
     'preprocess': commands.GatherProto,
 
-    'build_package_protos': grpc.tools.command.BuildPackageProtos,
+    'build_package_protos': grpc_tools.command.BuildPackageProtos,
     'build_py': commands.BuildPy,
     'run_interop': commands.RunInterop,
     'test_lite': commands.TestLite
diff --git a/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py b/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
index 80300d1..5dde72b 100644
--- a/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
+++ b/src/python/grpcio_tests/tests/health_check/_health_servicer_test.py
@@ -27,14 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Tests of grpc.health.v1.health."""
+"""Tests of grpc_health.v1.health."""
 
 import unittest
 
 import grpc
 from grpc.framework.foundation import logging_pool
-from grpc.health.v1 import health
-from grpc.health.v1 import health_pb2
+from grpc_health.v1 import health
+from grpc_health.v1 import health_pb2
 
 from tests.unit.framework.common import test_constants
 
diff --git a/src/python/grpcio_tests/tests/http2/_negative_http2_client.py b/src/python/grpcio_tests/tests/http2/_negative_http2_client.py
new file mode 100644
index 0000000..f860468
--- /dev/null
+++ b/src/python/grpcio_tests/tests/http2/_negative_http2_client.py
@@ -0,0 +1,153 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""The Python client used to test negative http2 conditions."""
+
+import argparse
+
+import grpc
+from src.proto.grpc.testing import test_pb2
+from src.proto.grpc.testing import messages_pb2
+
+def _validate_payload_type_and_length(response, expected_type, expected_length):
+  if response.payload.type is not expected_type:
+    raise ValueError(
+      'expected payload type %s, got %s' %
+          (expected_type, type(response.payload.type)))
+  elif len(response.payload.body) != expected_length:
+    raise ValueError(
+      'expected payload body size %d, got %d' %
+          (expected_length, len(response.payload.body)))
+
+def _expect_status_code(call, expected_code):
+  if call.code() != expected_code:
+    raise ValueError(
+      'expected code %s, got %s' % (expected_code, call.code()))
+
+def _expect_status_details(call, expected_details):
+  if call.details() != expected_details:
+    raise ValueError(
+      'expected message %s, got %s' % (expected_details, call.details()))
+
+def _validate_status_code_and_details(call, expected_code, expected_details):
+  _expect_status_code(call, expected_code)
+  _expect_status_details(call, expected_details)
+
+# common requests
+_REQUEST_SIZE = 314159
+_RESPONSE_SIZE = 271828
+
+_SIMPLE_REQUEST = messages_pb2.SimpleRequest(
+    response_type=messages_pb2.COMPRESSABLE,
+    response_size=_RESPONSE_SIZE,
+    payload=messages_pb2.Payload(body=b'\x00' * _REQUEST_SIZE))
+
+def _goaway(stub):
+  first_response = stub.UnaryCall(_SIMPLE_REQUEST)
+  _validate_payload_type_and_length(first_response, 
+      messages_pb2.COMPRESSABLE, _RESPONSE_SIZE)
+  second_response = stub.UnaryCall(_SIMPLE_REQUEST)
+  _validate_payload_type_and_length(second_response, 
+      messages_pb2.COMPRESSABLE, _RESPONSE_SIZE)
+
+def _rst_after_header(stub):
+  resp_future = stub.UnaryCall.future(_SIMPLE_REQUEST)
+  _validate_status_code_and_details(resp_future, grpc.StatusCode.UNAVAILABLE, "")
+
+def _rst_during_data(stub):
+  resp_future = stub.UnaryCall.future(_SIMPLE_REQUEST)
+  _validate_status_code_and_details(resp_future, grpc.StatusCode.UNKNOWN, "")
+
+def _rst_after_data(stub):
+  resp_future = stub.UnaryCall.future(_SIMPLE_REQUEST)
+  _validate_payload_type_and_length(next(resp_future),
+      messages_pb2.COMPRESSABLE, _RESPONSE_SIZE)
+  _validate_status_code_and_details(resp_future, grpc.StatusCode.UNKNOWN, "")
+
+def _ping(stub):
+  response = stub.UnaryCall(_SIMPLE_REQUEST)
+  _validate_payload_type_and_length(response, 
+      messages_pb2.COMPRESSABLE, _RESPONSE_SIZE)
+
+def _max_streams(stub):
+  # send one req to ensure server sets MAX_STREAMS
+  response = stub.UnaryCall(_SIMPLE_REQUEST)
+  _validate_payload_type_and_length(response, 
+      messages_pb2.COMPRESSABLE, _RESPONSE_SIZE)
+
+  # give the streams a workout
+  futures = []
+  for _ in range(15):
+    futures.append(stub.UnaryCall.future(_SIMPLE_REQUEST))
+  for future in futures:
+    _validate_payload_type_and_length(future.result(),
+        messages_pb2.COMPRESSABLE, _RESPONSE_SIZE)
+
+def _run_test_case(test_case, stub):
+  if test_case == 'goaway':
+    _goaway(stub)
+  elif test_case == 'rst_after_header':
+    _rst_after_header(stub)
+  elif test_case == 'rst_during_data':
+    _rst_during_data(stub)
+  elif test_case == 'rst_after_data':
+    _rst_after_data(stub)
+  elif test_case =='ping':
+    _ping(stub)
+  elif test_case == 'max_streams':
+    _max_streams(stub)
+  else:
+    raise ValueError("Invalid test case: %s" % test_case)
+
+def _args():
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      '--server_host', help='the host to which to connect', type=str,
+      default="127.0.0.1")
+  parser.add_argument(
+      '--server_port', help='the port to which to connect', type=int,
+      default="8080")
+  parser.add_argument(
+      '--test_case', help='the test case to execute', type=str,
+      default="goaway")
+  return parser.parse_args()
+
+def _stub(server_host, server_port):
+  target = '{}:{}'.format(server_host, server_port)
+  channel = grpc.insecure_channel(target)
+  return test_pb2.TestServiceStub(channel)
+
+def main():
+  args = _args()
+  stub = _stub(args.server_host, args.server_port)
+  _run_test_case(args.test_case, stub)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/src/python/grpcio_tests/tests/interop/_insecure_interop_test.py b/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py
similarity index 94%
rename from src/python/grpcio_tests/tests/interop/_insecure_interop_test.py
rename to src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py
index 936c895..4fb22b4 100644
--- a/src/python/grpcio_tests/tests/interop/_insecure_interop_test.py
+++ b/src/python/grpcio_tests/tests/interop/_insecure_intraop_test.py
@@ -35,13 +35,13 @@
 import grpc
 from src.proto.grpc.testing import test_pb2
 
-from tests.interop import _interop_test_case
+from tests.interop import _intraop_test_case
 from tests.interop import methods
 from tests.interop import server
 
 
-class InsecureInteropTest(
-    _interop_test_case.InteropTestCase,
+class InsecureIntraopTest(
+    _intraop_test_case.IntraopTestCase,
     unittest.TestCase):
 
   def setUp(self):
diff --git a/src/python/grpcio_tests/tests/interop/_interop_test_case.py b/src/python/grpcio_tests/tests/interop/_intraop_test_case.py
similarity index 98%
rename from src/python/grpcio_tests/tests/interop/_interop_test_case.py
rename to src/python/grpcio_tests/tests/interop/_intraop_test_case.py
index ccea17a..fe1c173 100644
--- a/src/python/grpcio_tests/tests/interop/_interop_test_case.py
+++ b/src/python/grpcio_tests/tests/interop/_intraop_test_case.py
@@ -32,7 +32,7 @@
 from tests.interop import methods
 
 
-class InteropTestCase(object):
+class IntraopTestCase(object):
   """Unit test methods.
 
   This class must be mixed in with unittest.TestCase and a class that defines
diff --git a/src/python/grpcio_tests/tests/interop/_secure_interop_test.py b/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py
similarity index 95%
rename from src/python/grpcio_tests/tests/interop/_secure_interop_test.py
rename to src/python/grpcio_tests/tests/interop/_secure_intraop_test.py
index eaca553..3665c69 100644
--- a/src/python/grpcio_tests/tests/interop/_secure_interop_test.py
+++ b/src/python/grpcio_tests/tests/interop/_secure_intraop_test.py
@@ -35,15 +35,15 @@
 import grpc
 from src.proto.grpc.testing import test_pb2
 
-from tests.interop import _interop_test_case
+from tests.interop import _intraop_test_case
 from tests.interop import methods
 from tests.interop import resources
 
 _SERVER_HOST_OVERRIDE = 'foo.test.google.fr'
 
 
-class SecureInteropTest(
-    _interop_test_case.InteropTestCase,
+class SecureIntraopTest(
+    _intraop_test_case.IntraopTestCase,
     unittest.TestCase):
 
   def setUp(self):
diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py
index 52e56f3..9038ae5 100644
--- a/src/python/grpcio_tests/tests/interop/methods.py
+++ b/src/python/grpcio_tests/tests/interop/methods.py
@@ -33,7 +33,6 @@
 import json
 import os
 import threading
-import time
 
 from oauth2client import client as oauth2client_client
 
@@ -196,16 +195,6 @@
         response, messages_pb2.COMPRESSABLE, sizes[index])
 
 
-def _cancel_after_begin(stub):
-  sizes = (27182, 8, 1828, 45904,)
-  payloads = (messages_pb2.Payload(body=b'\x00' * size) for size in sizes)
-  requests = (messages_pb2.StreamingInputCallRequest(payload=payload)
-              for payload in payloads)
-  response_future = stub.StreamingInputCall.future(requests)
-  response_future.cancel()
-  if not response_future.cancelled():
-    raise ValueError('expected call to be cancelled')
-
 
 class _Pipe(object):
 
@@ -265,6 +254,16 @@
           response, messages_pb2.COMPRESSABLE, response_size)
 
 
+def _cancel_after_begin(stub):
+  with _Pipe() as pipe:
+    response_future = stub.StreamingInputCall.future(pipe)
+    response_future.cancel()
+    if not response_future.cancelled():
+      raise ValueError('expected cancelled method to return True')
+    if response_future.code() is not grpc.StatusCode.CANCELLED:
+      raise ValueError('expected status code CANCELLED')
+
+
 def _cancel_after_first_response(stub):
   request_response_sizes = (31415, 9, 2653, 58979,)
   request_payload_sizes = (27182, 8, 1828, 45904,)
@@ -302,7 +301,6 @@
         response_type=messages_pb2.COMPRESSABLE,
         payload=messages_pb2.Payload(body=b'\x00' * request_payload_size))
     pipe.add(request)
-    time.sleep(0.1)
     try:
       next(response_iterator)
     except grpc.RpcError as rpc_error:
diff --git a/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py b/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
index 64fd972..f8ae05b 100644
--- a/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
+++ b/src/python/grpcio_tests/tests/protoc_plugin/_split_definitions_test.py
@@ -44,7 +44,7 @@
 import unittest
 
 import grpc
-from grpc.tools import protoc
+from grpc_tools import protoc
 from tests.unit.framework.common import test_constants
 
 _MESSAGES_IMPORT = b'import "messages.proto";'
diff --git a/src/python/grpcio_tests/tests/qps/benchmark_client.py b/src/python/grpcio_tests/tests/qps/benchmark_client.py
index 83b46c9..650e475 100644
--- a/src/python/grpcio_tests/tests/qps/benchmark_client.py
+++ b/src/python/grpcio_tests/tests/qps/benchmark_client.py
@@ -68,12 +68,8 @@
     else:
       channel = grpc.insecure_channel(server)
 
-    connected_event = threading.Event()
-    def wait_for_ready(connectivity):
-      if connectivity == grpc.ChannelConnectivity.READY:
-        connected_event.set()
-    channel.subscribe(wait_for_ready, try_to_connect=True)
-    connected_event.wait()
+    # waits for the channel to be ready before we start sending messages
+    grpc.channel_ready_future(channel).result()
 
     if config.payload_config.WhichOneof('payload') == 'simple_params':
       self._generic = False
diff --git a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
index 87264cf..43d6c97 100644
--- a/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
+++ b/src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
@@ -27,14 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Tests of grpc.reflection.v1alpha.reflection."""
+"""Tests of grpc_reflection.v1alpha.reflection."""
 
 import unittest
 
 import grpc
 from grpc.framework.foundation import logging_pool
-from grpc.reflection.v1alpha import reflection
-from grpc.reflection.v1alpha import reflection_pb2
+from grpc_reflection.v1alpha import reflection
+from grpc_reflection.v1alpha import reflection_pb2
 
 from google.protobuf import descriptor_pool
 from google.protobuf import descriptor_pb2
@@ -75,7 +75,7 @@
         file_by_filename='i-donut-exist'
       ),
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
@@ -93,7 +93,7 @@
         )
       ),
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
   def testFileBySymbol(self):
     requests = (
@@ -104,7 +104,7 @@
         file_containing_symbol='i.donut.exist.co.uk.org.net.me.name.foo'
       ),
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
@@ -122,7 +122,7 @@
         )
       ),
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
   @unittest.skip('TODO(atash): implement file-containing-extension reflection '
                  '(see https://github.com/google/protobuf/issues/2248)')
@@ -141,7 +141,7 @@
         ),
       ),
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
@@ -159,7 +159,7 @@
         )
       ),
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
   def testListServices(self):
     requests = (
@@ -167,7 +167,7 @@
         list_services='',
       ),
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
@@ -179,7 +179,7 @@
         )
       ),
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/stress/client.py b/src/python/grpcio_tests/tests/stress/client.py
index 390ea13..b811672 100644
--- a/src/python/grpcio_tests/tests/stress/client.py
+++ b/src/python/grpcio_tests/tests/stress/client.py
@@ -110,10 +110,13 @@
     channel_credentials = grpc.ssl_channel_credentials(
         root_certificates=root_certificates)
     options = (('grpc.ssl_target_name_override', args.server_host_override,),)
-    return grpc.secure_channel(
-        target, channel_credentials, options=options)
+    channel = grpc.secure_channel(target, channel_credentials, options=options)
   else:
-    return grpc.insecure_channel(target)
+    channel = grpc.insecure_channel(target)
+
+  # waits for the channel to be ready before we start sending messages
+  grpc.channel_ready_future(channel).result()
+  return channel
 
 def run_test(args):
   test_cases = _parse_weighted_test_cases(args.test_cases)
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 04a2e44..70d965d 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -1,7 +1,7 @@
 [
   "health_check._health_servicer_test.HealthServicerTest",
-  "interop._insecure_interop_test.InsecureInteropTest",
-  "interop._secure_interop_test.SecureInteropTest",
+  "interop._insecure_intraop_test.InsecureIntraopTest",
+  "interop._secure_intraop_test.SecureIntraopTest",
   "protoc_plugin._python_plugin_test.PythonPluginTest",
   "protoc_plugin._split_definitions_test.SameCommonTest",
   "protoc_plugin._split_definitions_test.SameSeparateTest",
@@ -27,7 +27,8 @@
   "unit._cython.cygrpc_test.TypeSmokeTest",
   "unit._empty_message_test.EmptyMessageTest",
   "unit._exit_test.ExitTest",
-  "unit._exit_test.ShutdownHandlerTest",
+  "unit._invalid_metadata_test.InvalidMetadataTest",
+  "unit._invocation_defects_test.InvocationDefectsTest",
   "unit._metadata_code_details_test.MetadataCodeDetailsTest",
   "unit._metadata_test.MetadataTest",
   "unit._rpc_test.RPCTest",
diff --git a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
index e0a7d15..46a964d 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_ready_future_test.py
@@ -64,7 +64,7 @@
     ready_future = grpc.channel_ready_future(channel)
     ready_future.add_done_callback(callback.accept_value)
     with self.assertRaises(grpc.FutureTimeoutError):
-      ready_future.result(test_constants.SHORT_TIMEOUT)
+      ready_future.result(timeout=test_constants.SHORT_TIMEOUT)
     self.assertFalse(ready_future.cancelled())
     self.assertFalse(ready_future.done())
     self.assertTrue(ready_future.running())
@@ -85,7 +85,7 @@
 
     ready_future = grpc.channel_ready_future(channel)
     ready_future.add_done_callback(callback.accept_value)
-    self.assertIsNone(ready_future.result(test_constants.SHORT_TIMEOUT))
+    self.assertIsNone(ready_future.result(timeout=test_constants.LONG_TIMEOUT))
     value_passed_to_callback = callback.block_until_called()
     self.assertIs(ready_future, value_passed_to_callback)
     self.assertFalse(ready_future.cancelled())
diff --git a/src/python/grpcio_tests/tests/unit/_compression_test.py b/src/python/grpcio_tests/tests/unit/_compression_test.py
index 83b9109..4d3f02e 100644
--- a/src/python/grpcio_tests/tests/unit/_compression_test.py
+++ b/src/python/grpcio_tests/tests/unit/_compression_test.py
@@ -125,7 +125,7 @@
     compressed_channel = grpc.insecure_channel('localhost:%d' % self._port,
         options=[('grpc.default_compression_algorithm', 1)])
     multi_callable = compressed_channel.stream_stream(_STREAM_STREAM)
-    call = multi_callable([request] * test_constants.STREAM_LENGTH)
+    call = multi_callable(iter([request] * test_constants.STREAM_LENGTH))
     for response in call:
       self.assertEqual(request, response)
 
diff --git a/src/python/grpcio_tests/tests/unit/_empty_message_test.py b/src/python/grpcio_tests/tests/unit/_empty_message_test.py
index 131f6e9..69f4689 100644
--- a/src/python/grpcio_tests/tests/unit/_empty_message_test.py
+++ b/src/python/grpcio_tests/tests/unit/_empty_message_test.py
@@ -123,12 +123,12 @@
 
   def testStreamUnary(self):
     response = self._channel.stream_unary(_STREAM_UNARY)(
-        [_REQUEST] * test_constants.STREAM_LENGTH)
+        iter([_REQUEST] * test_constants.STREAM_LENGTH))
     self.assertEqual(_RESPONSE, response)
 
   def testStreamStream(self):
     response_iterator = self._channel.stream_stream(_STREAM_STREAM)(
-        [_REQUEST] * test_constants.STREAM_LENGTH)
+        iter([_REQUEST] * test_constants.STREAM_LENGTH))
     self.assertSequenceEqual(
         [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator))
 
diff --git a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py
index b33802b..7775271 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_scenarios.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_scenarios.py
@@ -240,7 +240,7 @@
       multi_callable = channel.stream_unary(method)
       future = multi_callable.future(infinite_request_iterator())
       result, call = multi_callable.with_call(
-          [REQUEST] * test_constants.STREAM_LENGTH)
+          iter([REQUEST] * test_constants.STREAM_LENGTH))
     elif (args.scenario == IN_FLIGHT_STREAM_STREAM_CALL or
           args.scenario == IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL):
       multi_callable = channel.stream_stream(method)
diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py
index 342f5fc..5a4a328 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_test.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_test.py
@@ -43,8 +43,6 @@
 import time
 import unittest
 
-import grpc
-from grpc.framework.foundation import logging_pool
 from tests.unit import _exit_scenarios
 
 SCENARIO_FILE = os.path.abspath(os.path.join(
@@ -54,7 +52,7 @@
 BASE_SIGTERM_COMMAND = BASE_COMMAND + ['--wait_for_interrupt']
 
 INIT_TIME = 1.0
-SHUTDOWN_GRACE = 5.0
+
 
 processes = []
 process_lock = threading.Lock()
@@ -184,24 +182,5 @@
     interrupt_and_wait(process)
 
 
-class _ShutDownHandler(object):
-
-  def __init__(self):
-    self.seen_handler_grace = None
-
-  def shutdown_handler(self, handler_grace):
-    self.seen_handler_grace = handler_grace
-
-  
-class ShutdownHandlerTest(unittest.TestCase):
-
-  def test_shutdown_handler(self):
-    server = grpc.server(logging_pool.pool(1))
-    handler = _ShutDownHandler()
-    server.add_shutdown_handler(handler.shutdown_handler)
-    server.start()
-    server.stop(0, shutdown_handler_grace=SHUTDOWN_GRACE).wait()
-    self.assertEqual(SHUTDOWN_GRACE, handler.seen_handler_grace)
-
 if __name__ == '__main__':
   unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py b/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py
new file mode 100644
index 0000000..2dc225d
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_invalid_metadata_test.py
@@ -0,0 +1,175 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Test of RPCs made against gRPC Python's application-layer API."""
+
+import unittest
+
+import grpc
+
+from tests.unit.framework.common import test_constants
+
+_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2
+_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:]
+_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3
+_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3]
+
+_UNARY_UNARY = '/test/UnaryUnary'
+_UNARY_STREAM = '/test/UnaryStream'
+_STREAM_UNARY = '/test/StreamUnary'
+_STREAM_STREAM = '/test/StreamStream'
+
+
+def _unary_unary_multi_callable(channel):
+  return channel.unary_unary(_UNARY_UNARY)
+
+
+def _unary_stream_multi_callable(channel):
+  return channel.unary_stream(
+      _UNARY_STREAM,
+      request_serializer=_SERIALIZE_REQUEST,
+      response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_unary_multi_callable(channel):
+  return channel.stream_unary(
+      _STREAM_UNARY,
+      request_serializer=_SERIALIZE_REQUEST,
+      response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_stream_multi_callable(channel):
+  return channel.stream_stream(_STREAM_STREAM)
+
+
+class InvalidMetadataTest(unittest.TestCase):
+
+  def setUp(self):
+    self._channel = grpc.insecure_channel('localhost:8080')
+    self._unary_unary = _unary_unary_multi_callable(self._channel)
+    self._unary_stream = _unary_stream_multi_callable(self._channel)
+    self._stream_unary = _stream_unary_multi_callable(self._channel)
+    self._stream_stream = _stream_stream_multi_callable(self._channel)
+
+  def testUnaryRequestBlockingUnaryResponse(self):
+    request = b'\x07\x08'
+    metadata = (('InVaLiD', 'UnaryRequestBlockingUnaryResponse'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    with self.assertRaises(ValueError) as exception_context:
+      self._unary_unary(request, metadata=metadata)
+    self.assertIn(expected_error_details, str(exception_context.exception))
+
+  def testUnaryRequestBlockingUnaryResponseWithCall(self):
+    request = b'\x07\x08'
+    metadata = (('InVaLiD', 'UnaryRequestBlockingUnaryResponseWithCall'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    with self.assertRaises(ValueError) as exception_context:
+      self._unary_unary.with_call(request, metadata=metadata)
+    self.assertIn(expected_error_details, str(exception_context.exception))
+
+  def testUnaryRequestFutureUnaryResponse(self):
+    request = b'\x07\x08'
+    metadata = (('InVaLiD', 'UnaryRequestFutureUnaryResponse'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    response_future = self._unary_unary.future(request, metadata=metadata)
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      response_future.result()
+    self.assertEqual(
+        exception_context.exception.details(), expected_error_details)
+    self.assertEqual(
+        exception_context.exception.code(), grpc.StatusCode.INTERNAL)
+    self.assertEqual(response_future.details(), expected_error_details)
+    self.assertEqual(response_future.code(), grpc.StatusCode.INTERNAL)
+
+  def testUnaryRequestStreamResponse(self):
+    request = b'\x37\x58'
+    metadata = (('InVaLiD', 'UnaryRequestStreamResponse'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    response_iterator = self._unary_stream(request, metadata=metadata)
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      next(response_iterator)
+    self.assertEqual(
+        exception_context.exception.details(), expected_error_details)
+    self.assertEqual(
+        exception_context.exception.code(), grpc.StatusCode.INTERNAL)
+    self.assertEqual(response_iterator.details(), expected_error_details)
+    self.assertEqual(response_iterator.code(), grpc.StatusCode.INTERNAL)
+
+  def testStreamRequestBlockingUnaryResponse(self):
+    request_iterator = (b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
+    metadata = (('InVaLiD', 'StreamRequestBlockingUnaryResponse'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    with self.assertRaises(ValueError) as exception_context:
+      self._stream_unary(request_iterator, metadata=metadata)
+    self.assertIn(expected_error_details, str(exception_context.exception))
+
+  def testStreamRequestBlockingUnaryResponseWithCall(self):
+    request_iterator = (
+        b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
+    metadata = (('InVaLiD', 'StreamRequestBlockingUnaryResponseWithCall'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    multi_callable = _stream_unary_multi_callable(self._channel)
+    with self.assertRaises(ValueError) as exception_context:
+      multi_callable.with_call(request_iterator, metadata=metadata)
+    self.assertIn(expected_error_details, str(exception_context.exception))
+
+  def testStreamRequestFutureUnaryResponse(self):
+    request_iterator = (
+        b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
+    metadata = (('InVaLiD', 'StreamRequestFutureUnaryResponse'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    response_future = self._stream_unary.future(
+        request_iterator, metadata=metadata)
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      response_future.result()
+    self.assertEqual(
+        exception_context.exception.details(), expected_error_details)
+    self.assertEqual(
+        exception_context.exception.code(), grpc.StatusCode.INTERNAL)
+    self.assertEqual(response_future.details(), expected_error_details)
+    self.assertEqual(response_future.code(), grpc.StatusCode.INTERNAL)
+
+  def testStreamRequestStreamResponse(self):
+    request_iterator = (
+        b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH))
+    metadata = (('InVaLiD', 'StreamRequestStreamResponse'),)
+    expected_error_details = "metadata was invalid: %s" % metadata
+    response_iterator = self._stream_stream(request_iterator, metadata=metadata)
+    with self.assertRaises(grpc.RpcError) as exception_context:
+      next(response_iterator)
+    self.assertEqual(
+        exception_context.exception.details(), expected_error_details)
+    self.assertEqual(
+        exception_context.exception.code(), grpc.StatusCode.INTERNAL)
+    self.assertEqual(response_iterator.details(), expected_error_details)
+    self.assertEqual(response_iterator.code(), grpc.StatusCode.INTERNAL)
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
new file mode 100644
index 0000000..4312679
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
@@ -0,0 +1,247 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import itertools
+import threading
+import unittest
+from concurrent import futures
+
+import grpc
+from grpc.framework.foundation import logging_pool
+
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+
+_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2
+_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:]
+_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3
+_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3]
+
+_UNARY_UNARY = '/test/UnaryUnary'
+_UNARY_STREAM = '/test/UnaryStream'
+_STREAM_UNARY = '/test/StreamUnary'
+_STREAM_STREAM = '/test/StreamStream'
+
+
+class _Callback(object):
+  def __init__(self):
+    self._condition = threading.Condition()
+    self._value = None
+    self._called = False
+
+  def __call__(self, value):
+    with self._condition:
+      self._value = value
+      self._called = True
+      self._condition.notify_all()
+
+  def value(self):
+    with self._condition:
+      while not self._called:
+        self._condition.wait()
+      return self._value
+
+
+class _Handler(object):
+  def __init__(self, control):
+    self._control = control
+
+  def handle_unary_unary(self, request, servicer_context):
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+    return request
+
+  def handle_unary_stream(self, request, servicer_context):
+    for _ in range(test_constants.STREAM_LENGTH):
+      self._control.control()
+      yield request
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+
+  def handle_stream_unary(self, request_iterator, servicer_context):
+    if servicer_context is not None:
+      servicer_context.invocation_metadata()
+    self._control.control()
+    response_elements = []
+    for request in request_iterator:
+      self._control.control()
+      response_elements.append(request)
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+    return b''.join(response_elements)
+
+  def handle_stream_stream(self, request_iterator, servicer_context):
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+    for request in request_iterator:
+      self._control.control()
+      yield request
+    self._control.control()
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+  def __init__(
+    self, request_streaming, response_streaming, request_deserializer,
+    response_serializer, unary_unary, unary_stream, stream_unary,
+    stream_stream):
+    self.request_streaming = request_streaming
+    self.response_streaming = response_streaming
+    self.request_deserializer = request_deserializer
+    self.response_serializer = response_serializer
+    self.unary_unary = unary_unary
+    self.unary_stream = unary_stream
+    self.stream_unary = stream_unary
+    self.stream_stream = stream_stream
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+  def __init__(self, handler):
+    self._handler = handler
+
+  def service(self, handler_call_details):
+    if handler_call_details.method == _UNARY_UNARY:
+      return _MethodHandler(
+        False, False, None, None, self._handler.handle_unary_unary, None,
+        None, None)
+    elif handler_call_details.method == _UNARY_STREAM:
+      return _MethodHandler(
+        False, True, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None,
+        self._handler.handle_unary_stream, None, None)
+    elif handler_call_details.method == _STREAM_UNARY:
+      return _MethodHandler(
+        True, False, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None, None,
+        self._handler.handle_stream_unary, None)
+    elif handler_call_details.method == _STREAM_STREAM:
+      return _MethodHandler(
+        True, True, None, None, None, None, None,
+        self._handler.handle_stream_stream)
+    else:
+      return None
+
+
+class FailAfterFewIterationsCounter(object):
+    def __init__(self, high, bytestring):
+        self._current = 0
+        self._high = high
+        self._bytestring = bytestring
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        if self._current >= self._high:
+            raise Exception("This is a deliberate failure in a unit test.")
+        else:
+            self._current += 1
+            return self._bytestring
+
+
+def _unary_unary_multi_callable(channel):
+  return channel.unary_unary(_UNARY_UNARY)
+
+
+def _unary_stream_multi_callable(channel):
+  return channel.unary_stream(
+    _UNARY_STREAM,
+    request_serializer=_SERIALIZE_REQUEST,
+    response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_unary_multi_callable(channel):
+  return channel.stream_unary(
+    _STREAM_UNARY,
+    request_serializer=_SERIALIZE_REQUEST,
+    response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_stream_multi_callable(channel):
+  return channel.stream_stream(_STREAM_STREAM)
+
+
+class InvocationDefectsTest(unittest.TestCase):
+  def setUp(self):
+    self._control = test_control.PauseFailControl()
+    self._handler = _Handler(self._control)
+    self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+
+    self._server = grpc.server(self._server_pool)
+    port = self._server.add_insecure_port('[::]:0')
+    self._server.add_generic_rpc_handlers((_GenericHandler(self._handler),))
+    self._server.start()
+
+    self._channel = grpc.insecure_channel('localhost:%d' % port)
+
+  def tearDown(self):
+    self._server.stop(0)
+
+  def testIterableStreamRequestBlockingUnaryResponse(self):
+    requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)]
+    multi_callable = _stream_unary_multi_callable(self._channel)
+
+    with self.assertRaises(grpc.RpcError):
+      response = multi_callable(
+        requests,
+        metadata=(('test', 'IterableStreamRequestBlockingUnaryResponse'),))
+
+  def testIterableStreamRequestFutureUnaryResponse(self):
+    requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)]
+    multi_callable = _stream_unary_multi_callable(self._channel)
+    response_future = multi_callable.future(
+      requests,
+      metadata=(
+        ('test', 'IterableStreamRequestFutureUnaryResponse'),))
+
+    with self.assertRaises(grpc.RpcError):
+      response = response_future.result()
+
+  def testIterableStreamRequestStreamResponse(self):
+    requests = [b'\x77\x58' for _ in range(test_constants.STREAM_LENGTH)]
+    multi_callable = _stream_stream_multi_callable(self._channel)
+    response_iterator = multi_callable(
+      requests,
+      metadata=(('test', 'IterableStreamRequestStreamResponse'),))
+
+    with self.assertRaises(grpc.RpcError):
+      next(response_iterator)
+
+  def testIteratorStreamRequestStreamResponse(self):
+    requests_iterator = FailAfterFewIterationsCounter(
+      test_constants.STREAM_LENGTH // 2, b'\x07\x08')
+    multi_callable = _stream_stream_multi_callable(self._channel)
+    response_iterator = multi_callable(
+      requests_iterator,
+      metadata=(('test', 'IteratorStreamRequestStreamResponse'),))
+
+    with self.assertRaises(grpc.RpcError):
+      for _ in range(test_constants.STREAM_LENGTH // 2 + 1):
+        next(response_iterator)
diff --git a/src/python/grpcio_tests/tests/unit/_metadata_test.py b/src/python/grpcio_tests/tests/unit/_metadata_test.py
index da73476..caba53f 100644
--- a/src/python/grpcio_tests/tests/unit/_metadata_test.py
+++ b/src/python/grpcio_tests/tests/unit/_metadata_test.py
@@ -193,7 +193,7 @@
   def testStreamUnary(self):
     multi_callable = self._channel.stream_unary(_STREAM_UNARY)
     unused_response, call = multi_callable.with_call(
-        [_REQUEST] * test_constants.STREAM_LENGTH,
+        iter([_REQUEST] * test_constants.STREAM_LENGTH),
         metadata=_CLIENT_METADATA)
     self.assertTrue(test_common.metadata_transmitted(
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
@@ -202,7 +202,7 @@
 
   def testStreamStream(self):
     multi_callable = self._channel.stream_stream(_STREAM_STREAM)
-    call = multi_callable([_REQUEST] * test_constants.STREAM_LENGTH,
+    call = multi_callable(iter([_REQUEST] * test_constants.STREAM_LENGTH),
                           metadata=_CLIENT_METADATA)
     self.assertTrue(test_common.metadata_transmitted(
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
diff --git a/src/python/grpcio_tests/tests/unit/beta/_utilities_test.py b/src/python/grpcio_tests/tests/unit/beta/_utilities_test.py
index 90fe10c..9cce96c 100644
--- a/src/python/grpcio_tests/tests/unit/beta/_utilities_test.py
+++ b/src/python/grpcio_tests/tests/unit/beta/_utilities_test.py
@@ -66,7 +66,7 @@
     ready_future = utilities.channel_ready_future(channel)
     ready_future.add_done_callback(callback.accept_value)
     with self.assertRaises(future.TimeoutError):
-      ready_future.result(test_constants.SHORT_TIMEOUT)
+      ready_future.result(timeout=test_constants.SHORT_TIMEOUT)
     self.assertFalse(ready_future.cancelled())
     self.assertFalse(ready_future.done())
     self.assertTrue(ready_future.running())
@@ -88,7 +88,7 @@
       ready_future = utilities.channel_ready_future(channel)
       ready_future.add_done_callback(callback.accept_value)
       self.assertIsNone(
-          ready_future.result(test_constants.SHORT_TIMEOUT))
+          ready_future.result(timeout=test_constants.LONG_TIMEOUT))
       value_passed_to_callback = callback.block_until_called()
       self.assertIs(ready_future, value_passed_to_callback)
       self.assertFalse(ready_future.cancelled())
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index f97890e..47fd6d9 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -65,5 +65,6 @@
                GRPC_SLICE_LENGTH(next));
     grpc_slice_unref(next);
   }
+  grpc_byte_buffer_reader_destroy(&reader);
   return rb_string;
 }
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 2a6a246..c7b112c 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -37,6 +37,7 @@
 #include "rb_server.h"
 
 #include <grpc/grpc.h>
+#include <grpc/support/atm.h>
 #include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
 #include "rb_call.h"
@@ -59,22 +60,26 @@
   /* The actual server */
   grpc_server *wrapped;
   grpc_completion_queue *queue;
+  gpr_atm shutdown_started;
 } grpc_rb_server;
 
 static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) {
   grpc_event ev;
-  if (server->wrapped != NULL) {
-    grpc_server_shutdown_and_notify(server->wrapped, server->queue, NULL);
-    ev = rb_completion_queue_pluck(server->queue, NULL, deadline, NULL);
-    if (ev.type == GRPC_QUEUE_TIMEOUT) {
-      grpc_server_cancel_all_calls(server->wrapped);
-      rb_completion_queue_pluck(server->queue, NULL,
-                                gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  // This can be started by app or implicitly by GC. Avoid a race between these.
+  if (gpr_atm_full_fetch_add(&server->shutdown_started, (gpr_atm)1) == 0) {
+    if (server->wrapped != NULL) {
+      grpc_server_shutdown_and_notify(server->wrapped, server->queue, NULL);
+      ev = rb_completion_queue_pluck(server->queue, NULL, deadline, NULL);
+      if (ev.type == GRPC_QUEUE_TIMEOUT) {
+        grpc_server_cancel_all_calls(server->wrapped);
+        rb_completion_queue_pluck(server->queue, NULL,
+                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+      }
+      grpc_server_destroy(server->wrapped);
+      grpc_rb_completion_queue_destroy(server->queue);
+      server->wrapped = NULL;
+      server->queue = NULL;
     }
-    grpc_server_destroy(server->wrapped);
-    grpc_rb_completion_queue_destroy(server->queue);
-    server->wrapped = NULL;
-    server->queue = NULL;
   }
 }
 
@@ -115,6 +120,7 @@
 static VALUE grpc_rb_server_alloc(VALUE cls) {
   grpc_rb_server *wrapper = ALLOC(grpc_rb_server);
   wrapper->wrapped = NULL;
+  wrapper->shutdown_started = (gpr_atm)0;
   return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper);
 }
 
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 23b2bb7..f6998e1 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -35,9 +35,18 @@
   # either end of a GRPC connection.  When raised, it indicates that a status
   # error should be returned to the other end of a GRPC connection; when
   # caught it means that this end received a status error.
+  #
+  # There is also subclass of BadStatus in this module for each GRPC status.
+  # E.g., the GRPC::Cancelled class corresponds to status CANCELLED.
+  #
+  # See
+  # https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/status.h
+  # for detailed descriptions of each status code.
   class BadStatus < StandardError
     attr_reader :code, :details, :metadata
 
+    include GRPC::Core::StatusCodes
+
     # @param code [Numeric] the status code
     # @param details [String] the details of the exception
     # @param metadata [Hash] the error's metadata
@@ -55,9 +64,152 @@
     def to_status
       Struct::Status.new(code, details, @metadata)
     end
+
+    def self.new_status_exception(code, details = 'unkown cause', metadata = {})
+      codes = {}
+      codes[OK] = Ok
+      codes[CANCELLED] = Cancelled
+      codes[UNKNOWN] = Unknown
+      codes[INVALID_ARGUMENT] = InvalidArgument
+      codes[DEADLINE_EXCEEDED] = DeadlineExceeded
+      codes[NOT_FOUND] = NotFound
+      codes[ALREADY_EXISTS] = AlreadyExists
+      codes[PERMISSION_DENIED] =  PermissionDenied
+      codes[UNAUTHENTICATED] = Unauthenticated
+      codes[RESOURCE_EXHAUSTED] = ResourceExhausted
+      codes[FAILED_PRECONDITION] = FailedPrecondition
+      codes[ABORTED] = Aborted
+      codes[OUT_OF_RANGE] = OutOfRange
+      codes[UNIMPLEMENTED] =  Unimplemented
+      codes[INTERNAL] = Internal
+      codes[UNIMPLEMENTED] =  Unimplemented
+      codes[UNAVAILABLE] =  Unavailable
+      codes[DATA_LOSS] = DataLoss
+
+      if codes[code].nil?
+        BadStatus.new(code, details, metadata)
+      else
+        codes[code].new(details, metadata)
+      end
+    end
   end
 
-  # Cancelled is an exception class that indicates that an rpc was cancelled.
-  class Cancelled < StandardError
+  # GRPC status code corresponding to status OK
+  class Ok < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::OK, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status CANCELLED
+  class Cancelled < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::CANCELLED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status UNKNOWN
+  class Unknown < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::UNKNOWN, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status INVALID_ARGUMENT
+  class InvalidArgument < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::INVALID_ARGUMENT, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status DEADLINE_EXCEEDED
+  class DeadlineExceeded < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::DEADLINE_EXCEEDED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status NOT_FOUND
+  class NotFound < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::NOT_FOUND, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status ALREADY_EXISTS
+  class AlreadyExists < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::ALREADY_EXISTS, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status PERMISSION_DENIED
+  class PermissionDenied < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::PERMISSION_DENIED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status UNAUTHENTICATED
+  class Unauthenticated < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::UNAUTHENTICATED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status RESOURCE_EXHAUSTED
+  class ResourceExhausted < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::RESOURCE_EXHAUSTED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status FAILED_PRECONDITION
+  class FailedPrecondition < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::FAILED_PRECONDITION, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status ABORTED
+  class Aborted < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::ABORTED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status OUT_OF_RANGE
+  class OutOfRange < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::OUT_OF_RANGE, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status UNIMPLEMENTED
+  class Unimplemented < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::UNIMPLEMENTED, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status INTERNAL
+  class Internal < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::INTERNAL, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status UNAVAILABLE
+  class Unavailable < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::UNAVAILABLE, details, metadata)
+    end
+  end
+
+  # GRPC status code corresponding to status DATA_LOSS
+  class DataLoss < BadStatus
+    def initialize(details = 'unknown cause', metadata = {})
+      super(Core::StatusCodes::DATA_LOSS, details, metadata)
+    end
   end
 end
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index f5c426e..3b31f77 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -43,8 +43,8 @@
         GRPC.logger.debug("Failing with status #{status}")
         # raise BadStatus, propagating the metadata if present.
         md = status.metadata
-        fail GRPC::BadStatus.new(status.code, status.details, md),
-             "status code: #{status.code}, details: #{status.details}"
+        fail GRPC::BadStatus.new_status_exception(
+          status.code, status.details, md)
       end
       status
     end
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index d7cd9e6..adc77bb 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -200,6 +200,7 @@
             if is_client
               batch_result = @call.run_batch(RECV_STATUS_ON_CLIENT => nil)
               @call.status = batch_result.status
+              @call.trailing_metadata = @call.status.metadata if @call.status
               batch_result.check_status
               GRPC.logger.debug("bidi-read-loop: done status #{@call.status}")
             end
@@ -219,6 +220,10 @@
       GRPC.logger.debug('bidi-read-loop: finished')
       @reads_complete = true
       finished
+      # Make sure that the write loop is done done before finishing the call.
+      # Note that blocking is ok at this point because we've already received
+      # a status
+      @enq_th.join if is_client
     end
   end
 end
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index cd17aed..d46c4a1 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -119,7 +119,7 @@
       # Send back a UNKNOWN status to the client
       GRPC.logger.warn("failed handler: #{active_call}; sending status:UNKNOWN")
       GRPC.logger.warn(e)
-      send_status(active_call, UNKNOWN, 'unkown error handling call on server')
+      send_status(active_call, UNKNOWN, "#{e.class}: #{e.message}")
     end
 
     def assert_arity_matches(mth)
diff --git a/src/ruby/lib/grpc/generic/service.rb b/src/ruby/lib/grpc/generic/service.rb
index 7cb9f1c..f5a6b49 100644
--- a/src/ruby/lib/grpc/generic/service.rb
+++ b/src/ruby/lib/grpc/generic/service.rb
@@ -110,8 +110,9 @@
         rpc_descs[name] = RpcDesc.new(name, input, output,
                                       marshal_class_method,
                                       unmarshal_class_method)
-        define_method(name) do
-          fail GRPC::BadStatus, GRPC::Core::StatusCodes::UNIMPLEMENTED
+        define_method(GenericService.underscore(name.to_s).to_sym) do |_, _|
+          fail GRPC::BadStatus.new_status_exception(
+            GRPC::Core::StatusCodes::UNIMPLEMENTED)
         end
       end
 
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
index 4bce174..6b2d852 100644
--- a/src/ruby/pb/grpc/health/checker.rb
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -52,7 +52,9 @@
         @status_mutex.synchronize do
           status = @statuses["#{req.service}"]
         end
-        fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil?
+	if status.nil?
+          fail GRPC::BadStatus.new_status_exception(StatusCodes::NOT_FOUND)
+	end
         HealthCheckResponse.new(status: status)
       end
 
diff --git a/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb b/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
index fde328e..7d1072e 100644
--- a/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
+++ b/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb
@@ -54,6 +54,10 @@
         rpc :EmptyCall, Empty, Empty
         # One request followed by one response.
         rpc :UnaryCall, SimpleRequest, SimpleResponse
+        # One request followed by one response. Response has cache control
+        # headers set such that a caching HTTP proxy (such as GFE) can
+        # satisfy subsequent requests.
+        rpc :CacheableUnaryCall, SimpleRequest, SimpleResponse
         # One request followed by a sequence of responses (streamed download).
         # The server returns the payload with client desired type and sizes.
         rpc :StreamingOutputCall, StreamingOutputCallRequest, stream(StreamingOutputCallResponse)
@@ -69,6 +73,9 @@
         # stream of responses are returned to the client when the server starts with
         # first request.
         rpc :HalfDuplexCall, stream(StreamingOutputCallRequest), stream(StreamingOutputCallResponse)
+        # The test server will not implement this method. It will be used
+        # to test the behavior when clients call unimplemented methods.
+        rpc :UnimplementedCall, Empty, Empty
       end
 
       Stub = Service.rpc_stub_class
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 1e3ae65..9c4ee9c 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -158,14 +158,26 @@
 
     GRPC.logger.info("... connecting securely to #{address}")
     stub_opts[:channel_args].merge!(compression_channel_args)
-    Grpc::Testing::TestService::Stub.new(address, creds, **stub_opts)
+    if opts.test_case == "unimplemented_service"
+      Grpc::Testing::UnimplementedService::Stub.new(address, creds, **stub_opts)
+    else
+      Grpc::Testing::TestService::Stub.new(address, creds, **stub_opts)
+    end
   else
     GRPC.logger.info("... connecting insecurely to #{address}")
-    Grpc::Testing::TestService::Stub.new(
-      address,
-      :this_channel_is_insecure,
-      channel_args: compression_channel_args
-    )
+    if opts.test_case == "unimplemented_service"
+      Grpc::Testing::UnimplementedService::Stub.new(
+        address,
+        :this_channel_is_insecure,
+        channel_args: compression_channel_args
+      )
+    else
+      Grpc::Testing::TestService::Stub.new(
+        address,
+        :this_channel_is_insecure,
+        channel_args: compression_channel_args
+      )
+    end
   end
 end
 
@@ -459,11 +471,8 @@
     deadline = GRPC::Core::TimeConsts::from_relative_time(1)
     resps = @stub.full_duplex_call(enum.each_item, deadline: deadline)
     resps.each { } # wait to receive each request (or timeout)
-    fail 'Should have raised GRPC::BadStatus(DEADLINE_EXCEEDED)'
-  rescue GRPC::BadStatus => e
-    assert("#{__callee__}: status was wrong") do
-      e.code == GRPC::Core::StatusCodes::DEADLINE_EXCEEDED
-    end
+    fail 'Should have raised GRPC::DeadlineExceeded'
+  rescue GRPC::DeadlineExceeded
   end
 
   def empty_stream
@@ -505,6 +514,153 @@
     op.wait
   end
 
+  def unimplemented_method
+    begin
+      resp = @stub.unimplemented_call(Empty.new)
+    rescue GRPC::Unimplemented => e
+      return
+    rescue Exception => e
+      fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
+    end
+    fail AssertionError, "GRPC::Unimplemented should have been raised. Was not."
+  end
+
+  def unimplemented_service
+    begin
+      resp = @stub.unimplemented_call(Empty.new)
+    rescue GRPC::Unimplemented => e
+      return
+    rescue Exception => e
+      fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
+    end
+    fail AssertionError, "GRPC::Unimplemented should have been raised. Was not."
+  end
+
+  def status_code_and_message
+
+    # Function wide constants.
+    message = "test status method"
+    code = GRPC::Core::StatusCodes::UNKNOWN
+
+    # Testing with UnaryCall.
+    payload = Payload.new(type: :COMPRESSABLE, body: nulls(1))
+    echo_status = EchoStatus.new(code: code, message: message)
+    req = SimpleRequest.new(response_type: :COMPRESSABLE,
+			    response_size: 1,
+			    payload: payload,
+			    response_status: echo_status)
+    seen_correct_exception = false
+    begin
+      resp = @stub.unary_call(req)
+    rescue GRPC::Unknown => e
+      if e.details != message
+	      fail AssertionError,
+	        "Expected message #{message}. Received: #{e.details}"
+      end
+      seen_correct_exception = true
+    rescue Exception => e
+      fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
+    end
+
+    if not seen_correct_exception
+      fail AssertionError, "Did not see expected status from UnaryCall"
+    end
+
+    # testing with FullDuplex
+    req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters
+    duplex_req = req_cls.new(payload: Payload.new(body: nulls(1)),
+                  response_type: :COMPRESSABLE,
+                  response_parameters: [p_cls.new(size: 1)],
+                  response_status: echo_status)
+    seen_correct_exception = false
+    begin
+      resp = @stub.full_duplex_call([duplex_req])
+      resp.each { |r| }
+    rescue GRPC::Unknown => e
+      if e.details != message
+        fail AssertionError,
+          "Expected message #{message}. Received: #{e.details}"
+      end
+      seen_correct_exception = true
+    rescue Exception => e
+      fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
+    end
+
+    if not seen_correct_exception
+      fail AssertionError, "Did not see expected status from FullDuplexCall"
+    end
+
+  end
+
+
+  def custom_metadata
+
+    # Function wide constants
+    req_size, wanted_response_size = 271_828, 314_159
+    initial_metadata_key = "x-grpc-test-echo-initial"
+    initial_metadata_value = "test_initial_metadata_value"
+    trailing_metadata_key = "x-grpc-test-echo-trailing-bin"
+    trailing_metadata_value = "\x0a\x0b\x0a\x0b\x0a\x0b"
+
+    metadata = {
+      initial_metadata_key => initial_metadata_value,
+      trailing_metadata_key => trailing_metadata_value
+    }
+
+    # Testing with UnaryCall
+    payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
+    req = SimpleRequest.new(response_type: :COMPRESSABLE,
+			    response_size: wanted_response_size,
+			    payload: payload)
+
+    op = @stub.unary_call(req, metadata: metadata, return_op: true)
+    op.execute
+    if not op.metadata.has_key?(initial_metadata_key)
+      fail AssertionError, "Expected initial metadata. None received"
+    elsif op.metadata[initial_metadata_key] != metadata[initial_metadata_key]
+      fail AssertionError, 
+             "Expected initial metadata: #{metadata[initial_metadata_key]}. "\
+             "Received: #{op.metadata[initial_metadata_key]}"
+    end
+    if not op.trailing_metadata.has_key?(trailing_metadata_key)
+      fail AssertionError, "Expected trailing metadata. None received"
+    elsif op.trailing_metadata[trailing_metadata_key] !=
+          metadata[trailing_metadata_key]
+      fail AssertionError, 
+            "Expected trailing metadata: #{metadata[trailing_metadata_key]}. "\
+            "Received: #{op.trailing_metadata[trailing_metadata_key]}"
+    end
+
+    # Testing with FullDuplex
+    req_cls, p_cls = StreamingOutputCallRequest, ResponseParameters
+    duplex_req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
+                  response_type: :COMPRESSABLE,
+                  response_parameters: [p_cls.new(size: wanted_response_size)])
+
+    duplex_op = @stub.full_duplex_call([duplex_req], metadata: metadata,
+                                        return_op: true)
+    resp = duplex_op.execute
+    resp.each { |r| } # ensures that the server sends trailing data
+    duplex_op.wait
+    if not duplex_op.metadata.has_key?(initial_metadata_key)
+      fail AssertionError, "Expected initial metadata. None received"
+    elsif duplex_op.metadata[initial_metadata_key] !=
+          metadata[initial_metadata_key]
+      fail AssertionError,
+             "Expected initial metadata: #{metadata[initial_metadata_key]}. "\
+             "Received: #{duplex_op.metadata[initial_metadata_key]}"
+    end
+    if not duplex_op.trailing_metadata[trailing_metadata_key]
+      fail AssertionError, "Expected trailing metadata. None received"
+    elsif duplex_op.trailing_metadata[trailing_metadata_key] !=
+          metadata[trailing_metadata_key]
+      fail AssertionError, 
+          "Expected trailing metadata: #{metadata[trailing_metadata_key]}. "\
+          "Received: #{duplex_op.trailing_metadata[trailing_metadata_key]}"
+    end
+
+  end
+
   def all
     all_methods = NamedTests.instance_methods(false).map(&:to_s)
     all_methods.each do |m|
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 3f1e0a1..cc9b872 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -129,6 +129,27 @@
   [].pack('x' * l).force_encoding('ascii-8bit')
 end
 
+def maybe_echo_metadata(_call)
+  
+  # these are consistent for all interop tests
+  initial_metadata_key = "x-grpc-test-echo-initial"
+  trailing_metadata_key = "x-grpc-test-echo-trailing-bin"
+
+  if _call.metadata.has_key?(initial_metadata_key)
+    _call.metadata_to_send[initial_metadata_key] = _call.metadata[initial_metadata_key]
+  end
+  if _call.metadata.has_key?(trailing_metadata_key)
+    _call.output_metadata[trailing_metadata_key] = _call.metadata[trailing_metadata_key]
+  end
+end
+
+def maybe_echo_status_and_message(req)
+  unless req.response_status.nil?
+    fail GRPC::BadStatus.new_status_exception(
+        req.response_status.code, req.response_status.message)
+  end
+end
+
 # A FullDuplexEnumerator passes requests to a block and yields generated responses
 class FullDuplexEnumerator
   include Grpc::Testing
@@ -143,6 +164,7 @@
     begin
       cls = StreamingOutputCallResponse
       @requests.each do |req|
+        maybe_echo_status_and_message(req)
         req.response_parameters.each do |params|
           resp_size = params.size
           GRPC.logger.info("read a req, response size is #{resp_size}")
@@ -170,6 +192,8 @@
   end
 
   def unary_call(simple_req, _call)
+    maybe_echo_metadata(_call)
+    maybe_echo_status_and_message(simple_req)
     req_size = simple_req.response_size
     SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
                                             body: nulls(req_size)))
@@ -189,7 +213,8 @@
     end
   end
 
-  def full_duplex_call(reqs)
+  def full_duplex_call(reqs, _call)
+    maybe_echo_metadata(_call)
     # reqs is a lazy Enumerator of the requests sent by the client.
     FullDuplexEnumerator.new(reqs).each_item
   end
diff --git a/src/ruby/qps/client.rb b/src/ruby/qps/client.rb
index 8aed866..8171926 100644
--- a/src/ruby/qps/client.rb
+++ b/src/ruby/qps/client.rb
@@ -134,6 +134,7 @@
     resp = stub.streaming_call(q.each_item)
     start = Time.now
     q.push(req)
+    pushed_sentinal = false
     resp.each do |r|
       @histogram.add((Time.now-start)*1e9)
       if !@done
@@ -141,8 +142,9 @@
         start = Time.now
         q.push(req)
       else
-        q.push(self)
-        break
+        q.push(self) unless pushed_sentinal
+	# Continue polling on the responses to consume and release resources
+        pushed_sentinal = true
       end
     end
   end
diff --git a/src/ruby/spec/error_sanity_spec.rb b/src/ruby/spec/error_sanity_spec.rb
new file mode 100644
index 0000000..77e94a8
--- /dev/null
+++ b/src/ruby/spec/error_sanity_spec.rb
@@ -0,0 +1,64 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+require 'grpc'
+
+StatusCodes = GRPC::Core::StatusCodes
+
+describe StatusCodes do
+  # convert upper snake-case to camel case.
+  # e.g., DEADLINE_EXCEEDED -> DeadlineExceeded
+  def upper_snake_to_camel(name)
+    name.to_s.split('_').map(&:downcase).map(&:capitalize).join('')
+  end
+
+  StatusCodes.constants.each do |status_name|
+    it 'there is a subclass of BadStatus corresponding to StatusCode: ' \
+      "#{status_name} that has code: #{StatusCodes.const_get(status_name)}" do
+      camel_case = upper_snake_to_camel(status_name)
+      error_class = GRPC.const_get(camel_case)
+      # expect the error class to be a subclass of BadStatus
+      expect(error_class < GRPC::BadStatus)
+
+      error_object = error_class.new
+      # check that the code matches the int value of the error's constant
+      status_code = StatusCodes.const_get(status_name)
+      expect(error_object.code).to eq(status_code)
+
+      # check default parameters
+      expect(error_object.details).to eq('unknown cause')
+      expect(error_object.metadata).to eq({})
+
+      # check that the BadStatus factory for creates the correct
+      # exception too
+      from_factory = GRPC::BadStatus.new_status_exception(status_code)
+      expect(from_factory.is_a?(error_class)).to be(true)
+    end
+  end
+end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 607a4a3..b51b291 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -190,15 +190,14 @@
         end
         creds = GRPC::Core::CallCredentials.new(failing_auth)
 
-        error_occured = false
+        unauth_error_occured = false
         begin
           get_response(stub, credentials: creds)
-        rescue GRPC::BadStatus => e
-          error_occured = true
-          expect(e.code).to eq(GRPC::Core::StatusCodes::UNAUTHENTICATED)
+        rescue GRPC::Unauthenticated => e
+          unauth_error_occured = true
           expect(e.details.include?(error_message)).to be true
         end
-        expect(error_occured).to eq(true)
+        expect(unauth_error_occured).to eq(true)
 
         # Kill the server thread so tests can complete
         th.kill
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index a3f0efa..1ace721 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -48,7 +48,6 @@
     @bidi_streamer = RpcDesc.new('ss', Stream.new(Object.new),
                                  Stream.new(Object.new), 'encode', 'decode')
     @bs_code = INTERNAL
-    @no_reason = 'unkown error handling call on server'
     @ok_response = Object.new
   end
 
@@ -62,8 +61,9 @@
 
     it 'sends status UNKNOWN if other StandardErrors are raised' do
       expect(@call).to receive(:remote_read).once.and_return(Object.new)
-      expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
-                                                        false, metadata: {})
+      expect(@call).to receive(:send_status).once.with(UNKNOWN,
+                                                       arg_error_msg,
+                                                       false, metadata: {})
       this_desc.run_server_method(@call, method(:other_error))
     end
 
@@ -112,7 +112,7 @@
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
-        expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason,
+        expect(@call).to receive(:send_status).once.with(UNKNOWN, arg_error_msg,
                                                          false, metadata: {})
         @client_streamer.run_server_method(@call, method(:other_error_alt))
       end
@@ -174,8 +174,9 @@
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
+        error_msg = arg_error_msg(StandardError.new)
         expect(@call).to receive(:run_server_bidi).and_raise(StandardError)
-        expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason,
+        expect(@call).to receive(:send_status).once.with(UNKNOWN, error_msg,
                                                          false, metadata: {})
         @bidi_streamer.run_server_method(@call, method(:other_error_alt))
       end
@@ -342,4 +343,9 @@
   def other_error_alt(_call)
     fail(ArgumentError, 'other error')
   end
+
+  def arg_error_msg(error = nil)
+    error ||= ArgumentError.new('other error')
+    "#{error.class}: #{error.message}"
+  end
 end
diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb
index 48ccaee..69e8222 100644
--- a/src/ruby/spec/generic/rpc_server_pool_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb
@@ -94,18 +94,6 @@
       expect(q.pop).to be(o)
       p.stop
     end
-
-    it 'it throws an error if all of the workers have tasks to do' do
-      p = Pool.new(5)
-      p.start
-      job = proc {}
-      5.times do
-        expect(p.ready_for_work?).to be(true)
-        p.schedule(&job)
-      end
-      expect { p.schedule(&job) }.to raise_error
-      expect { p.schedule(&job) }.to raise_error
-    end
   end
 
   describe '#stop' do
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index c569479..806ea8c 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -408,21 +408,21 @@
         req = EchoMsg.new
         n = 20 # arbitrary, use as many to ensure the server pool is exceeded
         threads = []
-        bad_status_code = nil
+        one_failed_as_unavailable = false
         n.times do
           threads << Thread.new do
             stub = SlowStub.new(alt_host, :this_channel_is_insecure)
             begin
               stub.an_rpc(req)
-            rescue GRPC::BadStatus => e
-              bad_status_code = e.code
+            rescue GRPC::ResourceExhausted
+              one_failed_as_unavailable = true
             end
           end
         end
         threads.each(&:join)
         alt_srv.stop
         t.join
-        expect(bad_status_code).to be(StatusCodes::RESOURCE_EXHAUSTED)
+        expect(one_failed_as_unavailable).to be(true)
       end
     end
 
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index 4711e09..7195100 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -122,7 +122,7 @@
           checker.check(HCReq.new(service: t[:service]), nil)
         end
         expected_msg = /#{StatusCodes::NOT_FOUND}/
-        expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+        expect(&blk).to raise_error GRPC::NotFound, expected_msg
       end
     end
   end
@@ -141,7 +141,7 @@
           checker.check(HCReq.new(service: t[:service]), nil)
         end
         expected_msg = /#{StatusCodes::NOT_FOUND}/
-        expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+        expect(&blk).to raise_error GRPC::NotFound, expected_msg
       end
     end
   end
@@ -163,7 +163,7 @@
           checker.check(HCReq.new(service: t[:service]), nil)
         end
         expected_msg = /#{StatusCodes::NOT_FOUND}/
-        expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+        expect(&blk).to raise_error GRPC::NotFound, expected_msg
       end
     end
   end
@@ -214,7 +214,7 @@
         stub.check(HCReq.new(service: 'unknown'))
       end
       expected_msg = /#{StatusCodes::NOT_FOUND}/
-      expect(&blk).to raise_error GRPC::BadStatus, expected_msg
+      expect(&blk).to raise_error GRPC::NotFound, expected_msg
       @srv.stop
       t.join
     end
diff --git a/src/ruby/spec/spec_helper.rb b/src/ruby/spec/spec_helper.rb
index c891c1b..c2be0af 100644
--- a/src/ruby/spec/spec_helper.rb
+++ b/src/ruby/spec/spec_helper.rb
@@ -67,3 +67,5 @@
 end
 
 RSpec::Expectations.configuration.warn_about_potential_false_positives = false
+
+Thread.abort_on_exception = true
diff --git a/templates/BUILD.template b/templates/BUILD.template
deleted file mode 100644
index af23fb2..0000000
--- a/templates/BUILD.template
+++ /dev/null
@@ -1,256 +0,0 @@
-%YAML 1.2
---- |
-  # GRPC Bazel BUILD file.
-  # This currently builds C, C++ and Objective-C code.
-  # This file has been automatically generated from a template file.
-  # Please look at the templates directory instead.
-  # This file can be regenerated from the template by running
-  # tools/buildgen/generate_projects.sh
-  
-  # Copyright 2015, Google Inc.
-  # All rights reserved.
-  #
-  # Redistribution and use in source and binary forms, with or without
-  # modification, are permitted provided that the following conditions are
-  # met:
-  #
-  #     * Redistributions of source code must retain the above copyright
-  # notice, this list of conditions and the following disclaimer.
-  #     * Redistributions in binary form must reproduce the above
-  # copyright notice, this list of conditions and the following disclaimer
-  # in the documentation and/or other materials provided with the
-  # distribution.
-  #     * Neither the name of Google Inc. nor the names of its
-  # contributors may be used to endorse or promote products derived from
-  # this software without specific prior written permission.
-  #
-  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-  
-  licenses(["notice"])  # 3-clause BSD
-  
-  exports_files(["LICENSE"])
-  
-  package(default_visibility = ["//visibility:public"])
-  
-  <%!
-  def get_deps(target_dict):
-    deps = []
-    if target_dict.get('secure', False):
-      deps = [
-        "//external:libssl",
-      ]
-    if target_dict.get('build', None) == 'protoc':
-      deps.append("//external:protobuf_compiler")
-    if (target_dict['name'] == 'grpc++_unsecure' or
-        target_dict['name'] == 'grpc++' or
-        target_dict['name'] == 'grpc++_codegen_lib'):
-      deps.append("//external:protobuf_clib")
-    elif target_dict['name'] == 'grpc':
-      deps.append("//external:zlib")
-    for d in target_dict.get('deps', []):
-      if d.find('//') == 0 or d[0] == ':':
-        deps.append(d)
-      else:
-        deps.append(':%s' % (d))
-    return deps
-  %>
-
-  % for lib in libs:
-  % if lib.build in ("all", "protoc"):
-  ${cc_library(lib)}
-  % endif
-  % endfor
-  
-  % for lib in libs:
-  % if lib.name in ("grpc", "gpr"):
-  ${objc_library(lib)}
-  % endif
-  % endfor
-  
-  % for tgt in targets:
-  % if tgt.build == 'protoc':
-  ${cc_binary(tgt)}
-  % endif
-  % endfor
-  
-  <%def name="cc_library(lib)">
-  <%
-    lib_hdrs = lib.get("headers", [])
-    hdrs = [h for h in lib_hdrs if not h.startswith('third_party/nanopb')]
-    srcs = [s for s in lib.src if not s.startswith('third_party/nanopb')]
-    uses_nanopb = len(lib_hdrs) != len(hdrs) or len(srcs) != len(lib.src)
-  %>
-  cc_library(
-    name = "${lib.name}",
-    srcs = [
-  % for hdr in hdrs:
-      "${hdr}",
-  % endfor
-  % for src in srcs:
-      "${src}",
-  % endfor
-    ],
-    hdrs = [
-  % for hdr in lib.get("public_headers", []):
-      "${hdr}",
-  % endfor
-    ],
-    includes = [
-      "include",
-      ".",
-    ],
-    deps = [
-  % for dep in get_deps(lib):
-      "${dep}",
-  % endfor
-  % if uses_nanopb:
-      "//external:nanopb",
-  % endif
-    ],
-  % if lib.name in ("grpc", "grpc_unsecure"):
-    copts = [
-      "-std=gnu99",
-    ],
-  % endif
-  )
-  </%def>
-  
-  <%def name="objc_library(lib)">
-  <%
-    lib_hdrs = lib.get("headers", [])
-    hdrs = [h for h in lib_hdrs if not h.startswith('third_party/nanopb')]
-    srcs = [s for s in lib.src if not s.startswith('third_party/nanopb')]
-    uses_nanopb = len(lib_hdrs) != len(hdrs) or len(srcs) != len(lib.src)
-  %>
-  objc_library(
-    name = "${lib.name}_objc",
-    srcs = [
-  % for src in srcs:
-      "${src}",
-  % endfor
-    ],
-    hdrs = [
-  % for hdr in lib.get("public_headers", []):
-      "${hdr}",
-  % endfor
-  % for hdr in hdrs:
-      "${hdr}",
-  % endfor
-    ],
-    includes = [
-      "include",
-      ".",
-    ],
-    deps = [
-  % for dep in lib.get("deps", []):
-      ":${dep}_objc",
-  % endfor
-  % if lib.get('secure', False):
-      "//external:libssl_objc",
-  % endif
-  % if uses_nanopb:
-      "//external:nanopb",
-  % endif
-    ],
-  % if lib.get("baselib", false):
-    sdk_dylibs = ["libz"],
-  % endif
-  )
-  </%def>
-  
-  <%def name="cc_binary(tgt)">
-  cc_binary(
-    name = "${tgt.name}",
-    srcs = [
-  % for src in tgt.src:
-      "${src}",
-  % endfor
-    ],
-    deps = [
-  % for dep in get_deps(tgt):
-      "${dep}",
-  % endfor
-    ],
-  )
-  </%def>
-  
-  objc_path = "src/objective-c"
-  
-  rx_library_path = objc_path + "/RxLibrary"
-  
-  objc_library(
-    name = "rx_library",
-    hdrs = glob([
-      rx_library_path + "/*.h",
-      rx_library_path + "/transformations/*.h",
-    ]),
-    srcs = glob([
-      rx_library_path + "/*.m",
-      rx_library_path + "/transformations/*.m",
-    ]),
-    includes = [objc_path],
-    deps = [
-      ":rx_library_private",
-    ],
-  )
-  
-  objc_library(
-    name = "rx_library_private",
-    hdrs = glob([rx_library_path + "/private/*.h"]),
-    srcs = glob([rx_library_path + "/private/*.m"]),
-    visibility = ["//visibility:private"],
-  )
-  
-  objc_client_path = objc_path + "/GRPCClient"
-  
-  objc_library(
-    name = "grpc_client",
-    hdrs = glob([
-      objc_client_path + "/*.h",
-      objc_client_path + "/private/*.h",
-    ]),
-    srcs = glob([
-      objc_client_path + "/*.m",
-      objc_client_path + "/private/*.m",
-    ]),
-    includes = [objc_path],
-    bundles = [":gRPCCertificates"],
-    deps = [
-      ":grpc_objc",
-      ":rx_library",
-    ],
-  )
-  
-  objc_bundle_library(
-      # The choice of name is signicant here, since it determines the bundle name.
-      name = "gRPCCertificates",
-      resources = ["etc/roots.pem"],
-  )
-  
-  proto_objc_rpc_path = objc_path + "/ProtoRPC"
-  
-  objc_library(
-    name = "proto_objc_rpc",
-    hdrs = glob([
-      proto_objc_rpc_path + "/*.h",
-    ]),
-    srcs = glob([
-      proto_objc_rpc_path + "/*.m",
-    ]),
-    includes = [objc_path],
-    deps = [
-      ":grpc_client",
-      ":rx_library",
-      "//external:protobuf_objc",
-    ],
-  )
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index c3c636c..028c1b8 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -84,7 +84,13 @@
   set(gRPC_USE_PROTO_LITE OFF CACHE BOOL "Use the protobuf-lite library")
 
   if (MSVC)
-    add_definitions( -D_WIN32_WINNT=0x600 )
+    add_definitions(-D_WIN32_WINNT=0x600 -D_SCL_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS)
+    # needed to compile boringssl
+    add_definitions(/wd4464 /wd4623 /wd4668 /wd4701 /wd4702 /wd4777 /wd5027)
+    # needed to compile protobuf
+    add_definitions(/wd4065 /wd4506)
+    # TODO(jtattermusch): revisit C4267 occurrences throughout the code
+    add_definitions(/wd4267)
   endif()
 
   if (gRPC_USE_PROTO_LITE)
@@ -188,14 +194,19 @@
   endif()
 
   % for lib in libs:
-  % if lib.build in ["all", "protoc", "tool"]:
+  % if lib.build in ["all", "protoc", "tool"] and lib.language in ['c', 'c++']:
+  ## TODO(jtattermusch): grpc++_reflection includes .proto files
+  ## which is not yet supported and thus fails the entire build.
+  ## Re-enable once fixed.
+  % if lib.name != 'grpc++_reflection':
     ${cc_library(lib)}
     ${cc_install(lib)}
   % endif
+  % endif
   % endfor
 
   % for tgt in targets:
-  % if tgt.build in ["all", "protoc", "tool"]:
+  % if tgt.build in ["all", "protoc", "tool"] and tgt.language in ['c', 'c++']:
   ${cc_binary(tgt)}
   ${cc_install(tgt)}
   % endif
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 109de33..6f4db26 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -182,12 +182,19 @@
   endif
   STRIP ?= strip -x
   else
+  ifeq ($(SYSTEM),MINGW32)
+  ifeq ($(origin AR), default)
+  AR = ar rcs
+  endif
+  STRIP ?= strip --strip-unneeded
+  else
   ifeq ($(origin AR), default)
   AR = ar rcs
   endif
   STRIP ?= strip
   endif
   endif
+  endif
   INSTALL ?= install
   RM ?= rm -f
   PKG_CONFIG ?= pkg-config
@@ -392,6 +399,7 @@
   Libs.private: $(PC_LIBS_PRIVATE)
 
   ifeq ($(SYSTEM),MINGW32)
+  EXECUTABLE_SUFFIX = .exe
   SHARED_EXT_CORE = dll
   SHARED_EXT_CPP = dll
   SHARED_EXT_CSHARP = dll
@@ -400,6 +408,7 @@
   SHARED_VERSION_CPP = -${settings.cpp_version.major}
   SHARED_VERSION_CSHARP = -${settings.csharp_version.major}
   else ifeq ($(SYSTEM),Darwin)
+  EXECUTABLE_SUFFIX = 
   SHARED_EXT_CORE = dylib
   SHARED_EXT_CPP = dylib
   SHARED_EXT_CSHARP = dylib
@@ -408,6 +417,7 @@
   SHARED_VERSION_CPP =
   SHARED_VERSION_CSHARP =
   else
+  EXECUTABLE_SUFFIX = 
   SHARED_EXT_CORE = so.$(CORE_VERSION)
   SHARED_EXT_CPP = so.$(CPP_VERSION)
   SHARED_EXT_CSHARP = so.$(CSHARP_VERSION)
@@ -1196,7 +1206,7 @@
   $(GENDIR)/${p}.grpc.pb.cc: ${p}.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) ${' '.join('$(GENDIR)/%s.pb.cc $(GENDIR)/%s.grpc.pb.cc' % (q,q) for q in proto_deps.get(p, []))}
   	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+  	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
   endif
 
   % endfor
@@ -1293,9 +1303,9 @@
   % if not lib.get('external_deps', None):
   	$(E) "[INSTALL] Installing $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]})"
   	$(Q) $(INSTALL) -d $(prefix)/lib
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]})
+  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]})
   ifeq ($(SYSTEM),MINGW32)
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
+  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]})-dll.a $(prefix)/lib/lib${lib.name}.a
   else ifneq ($(SYSTEM),Darwin)
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) $(prefix)/lib/lib${lib.name}.so
@@ -1322,9 +1332,6 @@
   ${install_shared("csharp")}
 
   install-plugins: $(PROTOC_PLUGINS)
-  ifeq ($(SYSTEM),MINGW32)
-  	$(Q) false
-  else
   	$(E) "[INSTALL] Installing grpc protoc plugins"
   % for tgt in targets:
   % if tgt.build == 'protoc':
@@ -1332,7 +1339,6 @@
   	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/${tgt.name} $(prefix)/bin/${tgt.name}
   % endif
   % endfor
-  endif
 
   install-pkg-config_c: pc_c pc_c_unsecure
   	$(E) "[INSTALL] Installing C pkg-config files"
@@ -1513,8 +1519,8 @@
         assert dep_lib, 'lib %s not found (in %s)' % (dep, lib.name)
         link_libs = link_libs + ' -l' + dep
         lib_deps = lib_deps + ' $(LIBDIR)/$(CONFIG)/lib' + dep + '.$(SHARED_EXT_' + lang_to_var[dep_lib.language] + ')'
-        mingw_libs = mingw_libs + ' -l' + dep + '-imp'
-        mingw_lib_deps = mingw_lib_deps + ' $(LIBDIR)/$(CONFIG)/' + dep + '.$(SHARED_EXT_' + lang_to_var[dep_lib.language] + ')'
+        mingw_libs = mingw_libs + ' -l' + dep + '$(SHARED_VERSION_' + lang_to_var[dep_lib.language] + ')-dll'
+        mingw_lib_deps = mingw_lib_deps + ' $(LIBDIR)/$(CONFIG)/' + dep + '$(SHARED_VERSION_' + lang_to_var[dep_lib.language] + ').$(SHARED_EXT_' + lang_to_var[dep_lib.language] + ')'
 
     security = lib.get('secure', 'check')
     if security == True:
@@ -1546,17 +1552,17 @@
   ${out_mingbase}.$(SHARED_EXT_${lang_to_var[lib.language]}): $(LIB${lib.name.upper()}_OBJS) ${mingw_lib_deps}
   	$(E) "[LD]      Linking $@"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared ${lib.name}.def -Wl,--output-def=${out_mingbase}.def -Wl,--out-implib=${out_libbase}-dll.a -o ${out_mingbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${mingw_libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=${out_mingbase}.def -Wl,--out-implib=${out_libbase}-dll.a -o ${out_mingbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${mingw_libs}
   else
   ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}): $(LIB${lib.name.upper()}_OBJS) ${lib_deps}
   	$(E) "[LD]      Linking $@"
   	$(Q) mkdir -p `dirname $@`
   ifeq ($(SYSTEM),Darwin)
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]}) -dynamiclib -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) -dynamiclib -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
   else
   	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.core_version.major} -o ${out_libbase}.$(SHARED_EXT_${lang_to_var[lib.language]}) ${common}${link_libs}
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so.${settings.get(lang_to_var[lib.language].lower() + '_version').major}
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so.${settings.get(lang_to_var[lib.language].lower() + '_version').major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION_${lang_to_var[lib.language]}).$(SHARED_EXT_${lang_to_var[lib.language]}) ${out_libbase}.so
   endif
   endif
   % endif
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index e6592ac..851effc 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -39,18 +39,68 @@
   # Some of this file is built with the help of
   # https://n8.io/converting-a-c-library-to-gyp/
   {
+    'variables': {
+      'runtime%': 'node'
+    },
     'target_defaults': {
       'include_dirs': [
         '.',
         'include'
       ],
       'defines': [
-        'GRPC_UV'
+        'GPR_BACKWARDS_COMPATIBILITY_MODE'
       ],
       'conditions': [
+        ['runtime=="node"', {
+          'defines': [
+            'GRPC_UV'
+          ]
+        }],
+        ['OS!="win" and runtime=="electron"', {
+          "defines": [
+            'OPENSSL_NO_THREADS'
+          ]
+        }],
+        # This is the condition for using boringssl
+        ['OS=="win" or runtime=="electron"', {
+          "include_dirs": [
+            "third_party/boringssl/include"
+          ],
+          "defines": [
+            'OPENSSL_NO_ASM'
+          ]
+        }, {
+          # Based on logic above, we know that this must be a non-Windows system
+          'variables': {
+            # The output of "node --version" is "v[version]". We use cut to
+            # remove the first character.
+            'target%': '<!(node --version | cut -c2-)'
+          },
+          # Empirically, Node only exports ALPN symbols if its major version is >0.
+          # io.js always reports versions >0 and always exports ALPN symbols.
+          # Therefore, Node's major version will be truthy if and only if it
+          # supports ALPN. The target is "[major].[minor].[patch]". We split by
+          # periods and take the first field to get the major version.
+          'defines': [
+            'TSI_OPENSSL_ALPN_SUPPORT=<!(echo <(target) | cut -d. -f1)'
+          ],
+          'include_dirs': [
+            '<(node_root_dir)/deps/openssl/openssl/include',
+          ],
+          'conditions': [
+           ["target_arch=='ia32'", {
+               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
+           }],
+           ["target_arch=='x64'", {
+               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
+           }],
+           ["target_arch=='arm'", {
+               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
+           }]
+          ]
+        }],
         ['OS == "win"', {
           "include_dirs": [
-            "third_party/boringssl/include",
             "third_party/zlib"
           ],
           "defines": [
@@ -60,8 +110,6 @@
             'UNICODE',
             '_UNICODE',
             'NOMINMAX',
-            'OPENSSL_NO_ASM',
-            'GPR_BACKWARDS_COMPATIBILITY_MODE'
           ],
           "msvs_settings": {
             'VCCLCompilerTool': {
@@ -74,21 +122,8 @@
         }, { # OS != "win"
           'variables': {
             'config': '<!(echo $CONFIG)',
-            # The output of "node --version" is "v[version]". We use cut to
-            # remove the first character.
-            'target%': '<!(node --version | cut -c2-)'
           },
-            # Empirically, Node only exports ALPN symbols if its major version is >0.
-            # io.js always reports versions >0 and always exports ALPN symbols.
-            # Therefore, Node's major version will be truthy if and only if it
-            # supports ALPN. The target is "[major].[minor].[patch]". We split by
-            # periods and take the first field to get the major version.
-          'defines': [
-            'TSI_OPENSSL_ALPN_SUPPORT=<!(echo <(target) | cut -d. -f1)',
-            'GPR_BACKWARDS_COMPATIBILITY_MODE'
-          ],
           'include_dirs': [
-            '<(node_root_dir)/deps/openssl/openssl/include',
             '<(node_root_dir)/deps/zlib'
           ],
           'conditions': [
@@ -103,21 +138,42 @@
                 '-fprofile-arcs'
               ]
             }
-           ],
-           ["target_arch=='ia32'", {
-               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
-           }],
-           ["target_arch=='x64'", {
-               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
-           }],
-           ["target_arch=='arm'", {
-               "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
-           }]
+           ]
           ]
         }]
       ]
     },
     'conditions': [
+      ['OS=="win" or runtime=="electron"', {
+        'targets': [
+          % for module in node_modules:
+          % for lib in libs:
+          % if lib.name in module.transitive_deps and lib.name == 'boringssl':
+          {
+            'cflags': [
+              '-std=c99',
+              '-Wall',
+              '-Werror'
+            ],
+            'target_name': '${lib.name}',
+            'product_prefix': 'lib',
+            'type': 'static_library',
+            'dependencies': [
+              % for dep in getattr(lib, 'deps', []):
+              '${dep}',
+              % endfor
+            ],
+            'sources': [
+              % for source in lib.src:
+              '${source}',
+              % endfor
+            ]
+          },
+          % endif
+          % endfor
+          % endfor
+        ]
+      }],
       ['OS == "win"', {
         'targets': [
           {
@@ -143,10 +199,10 @@
               }
             ]
           },
-          # Only want to compile BoringSSL and zlib under Windows
+          # Only want to compile zlib under Windows
           % for module in node_modules:
           % for lib in libs:
-          % if lib.name in module.transitive_deps and lib.name in ('boringssl', 'z'):
+          % if lib.name in module.transitive_deps and lib.name == 'z':
           {
             'cflags': [
               '-std=c99',
@@ -223,6 +279,15 @@
           '-g'
         ],
         "conditions": [
+          ['OS=="win" or runtime=="electron"', {
+            'dependencies': [
+              % for dep in getattr(module, 'deps', []):
+              % if dep == 'boringssl':
+              "${dep}",
+              % endif
+              % endfor
+            ]
+          }],
           ['OS=="mac"', {
             'xcode_settings': {
               'MACOSX_DEPLOYMENT_TARGET': '10.9',
@@ -235,7 +300,7 @@
           ['OS=="win"', {
             'dependencies': [
               % for dep in getattr(module, 'deps', []):
-              % if dep in ('boringssl', 'z'):
+              % if dep == 'z':
               "${dep}",
               % endif
               % endfor
diff --git a/templates/config.m4.template b/templates/config.m4.template
index 5847d45..f5f1d23 100644
--- a/templates/config.m4.template
+++ b/templates/config.m4.template
@@ -7,9 +7,9 @@
     dnl Write more examples of tests here...
 
     dnl # --with-grpc -> add include path
-    PHP_ADD_INCLUDE(../../grpc/include)
-    PHP_ADD_INCLUDE(../../grpc/src/php/ext/grpc)
-    PHP_ADD_INCLUDE(../../grpc/third_party/boringssl/include)
+    PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/include)
+    PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/php/ext/grpc)
+    PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/third_party/boringssl/include)
 
     LIBS="-lpthread $LIBS"
 
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index fbad1a3..1b97d18 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -62,7 +62,7 @@
   %>
   Pod::Spec.new do |s|
     s.name     = 'gRPC-Core'
-    version = '1.0.1'
+    version = '1.0.2'
     s.version  = version
     s.summary  = 'Core cross-platform gRPC library, written in C'
     s.homepage = 'http://www.grpc.io'
@@ -71,7 +71,9 @@
 
     s.source = {
       :git => 'https://github.com/grpc/grpc.git',
-      :tag => "v#{version}",
+      # TODO(mxyan): Change back to "v#{version}" for next release
+      #:tag => "v#{version}",
+      :tag => "objective-c-v#{version}",
       # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
       :submodules => true,
     }
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index 62d61b7..82fbb69 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -29,7 +29,7 @@
     s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
-    s.add_dependency 'google-protobuf', '~> 3.0.2'
+    s.add_dependency 'google-protobuf', '~> 3.1.0'
     s.add_dependency 'googleauth',      '~> 0.5.1'
 
     s.add_development_dependency 'bundler',            '~> 1.9'
diff --git a/templates/package.json.template b/templates/package.json.template
index 81f39d2..316c28e 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -23,6 +23,7 @@
     "scripts": {
       "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js --exclude-path=src/node/.jshintignore",
       "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
+      "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell",
       "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
       "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
       "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build"
@@ -40,6 +41,7 @@
     "devDependencies": {
       "async": "^2.0.1",
       "body-parser": "^1.15.2",
+      "electron-mocha": "^3.1.1",
       "express": "^4.14.0",
       "google-auth-library": "^0.9.2",
       "google-protobuf": "^3.0.0",
@@ -52,7 +54,7 @@
       "poisson-process": "^0.2.1"
     },
     "engines": {
-      "node": ">=0.12.0"
+      "node": ">=1.1.0"
     },
     "binary": {
       "module_name": "grpc_node",
diff --git a/templates/tools/dockerfile/clang_format.include b/templates/tools/dockerfile/clang_format.include
new file mode 100644
index 0000000..9a2b60b
--- /dev/null
+++ b/templates/tools/dockerfile/clang_format.include
@@ -0,0 +1,5 @@
+RUN apt-get update && apt-get -y install wget
+RUN echo deb http://llvm.org/apt/wily/ llvm-toolchain-wily-3.8 main >> /etc/apt/sources.list
+RUN echo deb-src http://llvm.org/apt/wily/ llvm-toolchain-wily-3.8 main >> /etc/apt/sources.list
+RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key| apt-key add -
+RUN apt-get update && apt-get -y install clang-format-3.8
diff --git a/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template b/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template
new file mode 100644
index 0000000..8360fc1
--- /dev/null
+++ b/templates/tools/dockerfile/grpc_clang_format/Dockerfile.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM ubuntu:15.10
+  
+  <%include file="../clang_format.include"/>
+  ADD clang_format_all_the_things.sh /
+  CMD ["echo 'Run with tools/distrib/clang_format_code.sh'"]
+  
diff --git a/templates/tools/dockerfile/test/bazel/Dockerfile.template b/templates/tools/dockerfile/test/bazel/Dockerfile.template
new file mode 100644
index 0000000..82f90be
--- /dev/null
+++ b/templates/tools/dockerfile/test/bazel/Dockerfile.template
@@ -0,0 +1,48 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM ubuntu:15.10
+  
+  <%include file="../../apt_get_basic.include"/>
+
+  #========================
+  # Bazel installation
+  RUN apt-get install -y software-properties-common g++
+  RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
+  RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
+  RUN apt-get -y update
+  RUN apt-get -y install bazel
+
+  RUN mkdir -p /var/local/jenkins
+  
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
index 72b098f..ceaa9aa 100644
--- a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
@@ -28,10 +28,21 @@
   # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-  
+
   FROM debian:jessie
-  
+
   <%include file="../../apt_get_basic.include"/>
+
+  # Install Electron apt dependencies
+  RUN apt-get update && apt-get install -y ${'\\'}
+    libasound2 ${'\\'}
+    libgconf-2-4 ${'\\'}
+    libgtk2.0-0 ${'\\'}
+    libnss3 ${'\\'}
+    libxss1 ${'\\'}
+    libxtst6 ${'\\'}
+    xvfb
+
   <%include file="../../python_deps.include"/>
   <%include file="../../node_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
index 0168353..8617666 100644
--- a/templates/tools/dockerfile/test/sanity/Dockerfile.template
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -52,18 +52,12 @@
   # ./compile.sh without a local protoc dependency
   # TODO(mattkwong): install dependencies to support latest Bazel version if newer
   # version is needed
-  RUN git clone https://github.com/bazelbuild/bazel.git /bazel && \
+  RUN git clone https://github.com/bazelbuild/bazel.git /bazel && ${"\\"}
     cd /bazel && git checkout tags/0.4.1 && ./compile.sh
   RUN ln -s /bazel/output/bazel /bin/
   
-  #===================
-  # Docker "inception"
-  # Note this is quite the ugly hack.
-  # This makes sure that the docker binary we inject has its dependencies.
-  RUN curl https://get.docker.com/ | sh
-  RUN apt-get remove --purge -y docker-engine
-  
-  RUN mkdir /var/local/jenkins
+  <%include file="../../clang_format.include"/>
+  <%include file="../../run_tests_addons.include"/>
   
   # Define the default command.
   CMD ["bash"]
diff --git a/templates/tools/doxygen/Doxyfile.include b/templates/tools/doxygen/Doxyfile.include
index 8b0c528..e26ae2b 100644
--- a/templates/tools/doxygen/Doxyfile.include
+++ b/templates/tools/doxygen/Doxyfile.include
@@ -8,7 +8,10 @@
 <%def name="gen_doxyfile(libnames, packagename, collection, internal)">
 <%
   import itertools
+  import glob
+  import os
   targets = []
+  docpackage = packagename.replace('+', 'p').lower()
   for libname in libnames:
     target = None
     for p in collection:
@@ -16,6 +19,11 @@
         target = p
     assert(target)
     targets.append(target)
+  srcdoc = []
+  for dirpath, dirnames, filenames in os.walk('src/%s' % docpackage):
+    for filename in filenames:
+      if os.path.splitext(filename)[1] == '.md':
+        srcdoc.append(os.path.join(dirpath, filename))
 %>
 # Doxyfile 1.8.9.1
 
@@ -778,13 +786,20 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = ${' \\\n'.join(
-                               itertools.chain.from_iterable(
-			           target.public_headers +
-				   ([]
-				    if not internal
-				    else target.headers + target.src)
-			       for target in targets))}
+INPUT                  = ${
+    ' \\\n'.join(sorted(
+        itertools.chain(
+            itertools.chain.from_iterable(
+    			      target.public_headers +
+    				    ([]
+    				     if not internal
+    				     else target.headers + target.src)
+    			      for target in targets),
+            glob.glob('doc/*.md'),
+            glob.glob('doc/%s/*.md' % docpackage),
+            [] if not internal else srcdoc)
+    ))
+}
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/templates/tools/run_tests/configs.json.template b/templates/tools/run_tests/generated/configs.json.template
similarity index 100%
rename from templates/tools/run_tests/configs.json.template
rename to templates/tools/run_tests/generated/configs.json.template
diff --git a/templates/tools/run_tests/sources_and_headers.json.template b/templates/tools/run_tests/generated/sources_and_headers.json.template
similarity index 100%
rename from templates/tools/run_tests/sources_and_headers.json.template
rename to templates/tools/run_tests/generated/sources_and_headers.json.template
diff --git a/templates/tools/run_tests/tests.json.template b/templates/tools/run_tests/generated/tests.json.template
similarity index 100%
rename from templates/tools/run_tests/tests.json.template
rename to templates/tools/run_tests/generated/tests.json.template
diff --git a/templates/vsprojects/grpc.sln.template b/templates/vsprojects/grpc.sln.template
index ded9838..0b28e93 100644
--- a/templates/vsprojects/grpc.sln.template
+++ b/templates/vsprojects/grpc.sln.template
@@ -2,6 +2,6 @@
 --- |
   <%namespace file="sln_defs.include" import="gen_solution"/>\
   <%
-  solution_projects = [p for p in vsprojects if p.build not in ['protoc', 'test', 'fuzzer'] and p.language in ['c', 'c++'] and p.vs_proj_dir == '.' and not (p.build == 'private' and p.language == 'c++')]
+  solution_projects = [p for p in vsprojects if p.build not in ['protoc', 'test', 'fuzzer'] and p.language in ['c', 'c++'] and p.vs_proj_dir == '.' and not (p.build == 'private' and p.language == 'c++') and not p.name in ['z', 'boringssl', 'grpc++_reflection']]
   %>\
   ${gen_solution(solution_projects, use_dlls='yes')}
diff --git a/src/python/grpcio_reflection/grpc/__init__.py b/test/core/bad_client/BUILD
similarity index 94%
copy from src/python/grpcio_reflection/grpc/__init__.py
copy to test/core/bad_client/BUILD
index 70ac5ed..5406eb9 100644
--- a/src/python/grpcio_reflection/grpc/__init__.py
+++ b/test/core/bad_client/BUILD
@@ -27,4 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-__import__('pkg_resources').declare_namespace(__name__)
+load(":generate_tests.bzl", "grpc_bad_client_tests")
+
+grpc_bad_client_tests()
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 07fcd99..a840868 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -33,15 +33,18 @@
 
 #include "test/core/bad_client/bad_client.h"
 
+#include <stdio.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
-#include <stdio.h>
+
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint_pair.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/murmur_hash.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/completion_queue.h"
@@ -117,7 +120,7 @@
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("bad_client_test");
   sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
 
   /* Create server, completion events */
   a.server = grpc_server_create(NULL, NULL);
@@ -148,7 +151,8 @@
 
   grpc_slice_buffer_init(&outgoing);
   grpc_slice_buffer_add(&outgoing, slice);
-  grpc_closure_init(&done_write_closure, done_write, &a);
+  grpc_closure_init(&done_write_closure, done_write, &a,
+                    grpc_schedule_on_exec_ctx);
 
   /* Write data */
   grpc_endpoint_write(&exec_ctx, sfd.client, &outgoing, &done_write_closure);
@@ -175,13 +179,14 @@
       grpc_slice_buffer_init(&args.incoming);
       gpr_event_init(&args.read_done);
       grpc_closure read_done_closure;
-      grpc_closure_init(&read_done_closure, read_done, &args);
+      grpc_closure_init(&read_done_closure, read_done, &args,
+                        grpc_schedule_on_exec_ctx);
       grpc_endpoint_read(&exec_ctx, sfd.client, &args.incoming,
                          &read_done_closure);
       grpc_exec_ctx_finish(&exec_ctx);
       GPR_ASSERT(
           gpr_event_wait(&args.read_done, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5)));
-      grpc_slice_buffer_destroy(&args.incoming);
+      grpc_slice_buffer_destroy_internal(&exec_ctx, &args.incoming);
     }
     // Shutdown.
     grpc_endpoint_shutdown(&exec_ctx, sfd.client);
@@ -194,7 +199,7 @@
                  .type == GRPC_OP_COMPLETE);
   grpc_server_destroy(a.server);
   grpc_completion_queue_destroy(a.cq);
-  grpc_slice_buffer_destroy(&outgoing);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &outgoing);
 
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/bad_client/generate_tests.bzl b/test/core/bad_client/generate_tests.bzl
new file mode 100755
index 0000000..694ddee
--- /dev/null
+++ b/test/core/bad_client/generate_tests.bzl
@@ -0,0 +1,68 @@
+#!/usr/bin/env python2.7
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Generates the appropriate build.json data for all the bad_client tests."""
+
+
+def test_options():
+  return struct()
+
+
+# maps test names to options
+BAD_CLIENT_TESTS = {
+    'badreq': test_options(),
+    'connection_prefix': test_options(),
+    'headers': test_options(),
+    'initial_settings_frame': test_options(),
+    'head_of_line_blocking': test_options(),
+    'large_metadata': test_options(),
+    'server_registered_method': test_options(),
+    'simple_request': test_options(),
+    'window_overflow': test_options(),
+    'unknown_frame': test_options(),
+}
+
+def grpc_bad_client_tests():
+  native.cc_library(
+      name = 'bad_client_test',
+      srcs = ['bad_client.c'],
+      hdrs = ['bad_client.h'],
+      copts = ['-std=c99'],
+      deps = ['//test/core/util:grpc_test_util', '//:grpc', '//:gpr', '//test/core/end2end:cq_verifier']
+  )
+  for t, topt in BAD_CLIENT_TESTS.items():
+    native.cc_test(
+        name = '%s_bad_client_test' % t,
+        srcs = ['tests/%s.c' % t],
+        deps = [':bad_client_test'],
+        copts = ['-std=c99'],
+    )
+
diff --git a/src/python/grpcio_reflection/grpc/__init__.py b/test/core/bad_ssl/BUILD
similarity index 94%
copy from src/python/grpcio_reflection/grpc/__init__.py
copy to test/core/bad_ssl/BUILD
index 70ac5ed..630733d 100644
--- a/src/python/grpcio_reflection/grpc/__init__.py
+++ b/test/core/bad_ssl/BUILD
@@ -27,4 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-__import__('pkg_resources').declare_namespace(__name__)
+load(":generate_tests.bzl", "grpc_bad_ssl_tests")
+
+grpc_bad_ssl_tests()
diff --git a/tools/run_tests/post_tests_csharp.sh b/test/core/bad_ssl/generate_tests.bzl
similarity index 72%
copy from tools/run_tests/post_tests_csharp.sh
copy to test/core/bad_ssl/generate_tests.bzl
index bb6f5c6..78474bc 100755
--- a/tools/run_tests/post_tests_csharp.sh
+++ b/test/core/bad_ssl/generate_tests.bzl
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env python2.7
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -28,17 +28,25 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
 
-if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+def test_options():
+  return struct()
 
-# change to gRPC repo root
-cd $(dirname $0)/../..
 
-# Generate the csharp extension coverage report
-gcov objs/gcov/src/csharp/ext/*.o
-lcov --base-directory . --directory . -c -o coverage.info
-lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info
-genhtml -o reports/csharp_ext_coverage --num-spaces 2 \
-  -t 'gRPC C# native extension test coverage' coverage.info \
-  --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix
+# maps test names to options
+BAD_SSL_TESTS = ['cert', 'alpn']
+
+def grpc_bad_ssl_tests():
+  native.cc_library(
+      name = 'bad_ssl_test_server',
+      srcs = ['server_common.c'],
+      hdrs = ['server_common.h'],
+      deps = ['//test/core/util:grpc_test_util', '//:grpc', '//test/core/end2end:ssl_test_data']
+  )
+  for t in BAD_SSL_TESTS:
+    native.cc_test(
+        name = 'bad_ssl_%s_server' % t,
+        srcs = ['servers/%s.c' % t],
+        deps = [':bad_ssl_test_server'],
+    )
+
diff --git a/test/core/channel/channel_args_test.c b/test/core/channel/channel_args_test.c
index d3eb969..b2c4165 100644
--- a/test/core/channel/channel_args_test.c
+++ b/test/core/channel/channel_args_test.c
@@ -37,10 +37,12 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/channel/channel_args.h"
-
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/util/test_config.h"
 
 static void test_create(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
   grpc_arg arg_int;
   grpc_arg arg_string;
   grpc_arg to_add[2];
@@ -68,10 +70,12 @@
   GPR_ASSERT(strcmp(ch_args->args[1].value.string, arg_string.value.string) ==
              0);
 
-  grpc_channel_args_destroy(ch_args);
+  grpc_channel_args_destroy(&exec_ctx, ch_args);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_set_compression_algorithm(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_channel_args *ch_args;
 
   ch_args =
@@ -81,10 +85,12 @@
                     GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM) == 0);
   GPR_ASSERT(ch_args->args[0].type == GRPC_ARG_INTEGER);
 
-  grpc_channel_args_destroy(ch_args);
+  grpc_channel_args_destroy(&exec_ctx, ch_args);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_compression_algorithm_states(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_channel_args *ch_args, *ch_args_wo_gzip, *ch_args_wo_gzip_deflate;
   unsigned states_bitset;
   size_t i;
@@ -100,10 +106,10 @@
 
   /* disable gzip and deflate */
   ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
-      &ch_args, GRPC_COMPRESS_GZIP, 0);
+      &exec_ctx, &ch_args, GRPC_COMPRESS_GZIP, 0);
   GPR_ASSERT(ch_args == ch_args_wo_gzip);
   ch_args_wo_gzip_deflate = grpc_channel_args_compression_algorithm_set_state(
-      &ch_args_wo_gzip, GRPC_COMPRESS_DEFLATE, 0);
+      &exec_ctx, &ch_args_wo_gzip, GRPC_COMPRESS_DEFLATE, 0);
   GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate);
 
   states_bitset = (unsigned)grpc_channel_args_compression_algorithm_get_states(
@@ -118,7 +124,7 @@
 
   /* re-enabled gzip only */
   ch_args_wo_gzip = grpc_channel_args_compression_algorithm_set_state(
-      &ch_args_wo_gzip_deflate, GRPC_COMPRESS_GZIP, 1);
+      &exec_ctx, &ch_args_wo_gzip_deflate, GRPC_COMPRESS_GZIP, 1);
   GPR_ASSERT(ch_args_wo_gzip == ch_args_wo_gzip_deflate);
 
   states_bitset = (unsigned)grpc_channel_args_compression_algorithm_get_states(
@@ -131,7 +137,8 @@
     }
   }
 
-  grpc_channel_args_destroy(ch_args);
+  grpc_channel_args_destroy(&exec_ctx, ch_args);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_set_socket_mutator(void) {
@@ -144,7 +151,11 @@
   GPR_ASSERT(strcmp(ch_args->args[0].key, GRPC_ARG_SOCKET_MUTATOR) == 0);
   GPR_ASSERT(ch_args->args[0].type == GRPC_ARG_POINTER);
 
-  grpc_channel_args_destroy(ch_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, ch_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index 0840820..080c56f 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -41,9 +41,9 @@
 
 #include "test/core/util/test_config.h"
 
-static void channel_init_func(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
+static grpc_error *channel_init_func(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
   GPR_ASSERT(args->channel_args->num_args == 1);
   GPR_ASSERT(args->channel_args->args[0].type == GRPC_ARG_INTEGER);
   GPR_ASSERT(0 == strcmp(args->channel_args->args[0].key, "test_key"));
@@ -51,6 +51,7 @@
   GPR_ASSERT(args->is_first);
   GPR_ASSERT(args->is_last);
   *(int *)(elem->channel_data) = 0;
+  return GRPC_ERROR_NONE;
 }
 
 static grpc_error *call_init_func(grpc_exec_ctx *exec_ctx,
@@ -156,8 +157,8 @@
 
   GRPC_CHANNEL_STACK_UNREF(&exec_ctx, channel_stack, "done");
 
+  GRPC_MDSTR_UNREF(&exec_ctx, path);
   grpc_exec_ctx_finish(&exec_ctx);
-  GRPC_MDSTR_UNREF(path);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c
index 6e4058f..f46982a 100644
--- a/test/core/client_channel/lb_policies_test.c
+++ b/test/core/client_channel/lb_policies_test.c
@@ -241,6 +241,8 @@
   res.n = n;
   res.connections = gpr_malloc(sizeof(*res.connections) * n);
   res.connectivity_states = gpr_malloc(sizeof(*res.connectivity_states) * n);
+  memset(res.connections, 0, sizeof(*res.connections) * n);
+  memset(res.connectivity_states, 0, sizeof(*res.connectivity_states) * n);
   return res;
 }
 
@@ -643,7 +645,11 @@
   arg.value.string = "{\"loadBalancingPolicy\": \"ROUND_ROBIN\"}";
   grpc_channel_args *args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
   channel = grpc_insecure_channel_create("ipv4:127.0.0.1:1234", args, NULL);
-  grpc_channel_args_destroy(args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   // Ensures that resolver returns.
   grpc_channel_check_connectivity_state(channel, true /* try_to_connect */);
   // Now request the service config again.
@@ -782,17 +788,15 @@
     }
   }
 
-  /* no server is ever available. The persistent state is TRANSIENT_FAILURE. May
-   * also be CONNECTING if, under load, this check took too long to run and some
-   * subchannel already transitioned to retrying. */
+  /* No server is ever available. There should be no READY states (or SHUTDOWN).
+   * Note that all other states (IDLE, CONNECTING, TRANSIENT_FAILURE) are still
+   * possible, as the policy transitions while attempting to reconnect. */
   for (size_t i = 0; i < sequences->n; i++) {
     const grpc_connectivity_state actual = sequences->connectivity_states[i];
-    if (actual != GRPC_CHANNEL_TRANSIENT_FAILURE &&
-        actual != GRPC_CHANNEL_CONNECTING) {
+    if (actual == GRPC_CHANNEL_READY || actual == GRPC_CHANNEL_SHUTDOWN) {
       gpr_log(GPR_ERROR,
-              "CONNECTIVITY STATUS SEQUENCE FAILURE: expected "
-              "GRPC_CHANNEL_TRANSIENT_FAILURE or GRPC_CHANNEL_CONNECTING, got "
-              "'%s' at iteration #%d",
+              "CONNECTIVITY STATUS SEQUENCE FAILURE: got unexpected state "
+              "'%s' at iteration #%d.",
               grpc_connectivity_state_name(actual), (int)i);
       abort();
     }
@@ -841,17 +845,15 @@
     abort();
   }
 
-  /* ... and that the last one should be TRANSIENT_FAILURE, after all servers
-   * are gone. May also be CONNECTING if, under load, this check took too long
-   * to run and the subchannel already transitioned to retrying. */
+  /* ... and that the last one shouldn't be READY (or SHUTDOWN): all servers are
+   * gone. It may be all other states (IDLE, CONNECTING, TRANSIENT_FAILURE), as
+   * the policy transitions while attempting to reconnect. */
   actual = sequences->connectivity_states[num_iters - 1];
   for (i = 0; i < sequences->n; i++) {
-    if (actual != GRPC_CHANNEL_TRANSIENT_FAILURE &&
-        actual != GRPC_CHANNEL_CONNECTING) {
+    if (actual == GRPC_CHANNEL_READY || actual == GRPC_CHANNEL_SHUTDOWN) {
       gpr_log(GPR_ERROR,
-              "CONNECTIVITY STATUS SEQUENCE FAILURE: expected "
-              "GRPC_CHANNEL_TRANSIENT_FAILURE or GRPC_CHANNEL_CONNECTING, got "
-              "'%s' at iteration #%d",
+              "CONNECTIVITY STATUS SEQUENCE FAILURE: got unexpected state "
+              "'%s' at iteration #%d.",
               grpc_connectivity_state_name(actual), (int)i);
       abort();
     }
@@ -948,8 +950,8 @@
   const size_t NUM_ITERS = 10;
   const size_t NUM_SERVERS = 4;
 
-  grpc_test_init(argc, argv);
   grpc_init();
+  grpc_test_init(argc, argv);
   grpc_tracer_set_enabled("round_robin", 1);
 
   GPR_ASSERT(grpc_lb_policy_create(&exec_ctx, "this-lb-policy-does-not-exist",
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
index ffa167a..f0c6843 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.c
@@ -63,7 +63,8 @@
   }
 }
 
-static grpc_resolver *create_resolver(const char *name) {
+static grpc_resolver *create_resolver(grpc_exec_ctx *exec_ctx,
+                                      const char *name) {
   grpc_resolver_factory *factory = grpc_resolver_factory_lookup("dns");
   grpc_uri *uri = grpc_uri_parse(name, 0);
   GPR_ASSERT(uri);
@@ -71,7 +72,7 @@
   memset(&args, 0, sizeof(args));
   args.uri = uri;
   grpc_resolver *resolver =
-      grpc_resolver_factory_create_resolver(factory, &args);
+      grpc_resolver_factory_create_resolver(exec_ctx, factory, &args);
   grpc_resolver_factory_unref(factory);
   grpc_uri_destroy(uri);
   return resolver;
@@ -101,29 +102,29 @@
   grpc_init();
   gpr_mu_init(&g_mu);
   grpc_blocking_resolve_address = my_resolve_address;
-
-  grpc_resolver *resolver = create_resolver("dns:test");
-
   grpc_channel_args *result = (grpc_channel_args *)1;
 
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_resolver *resolver = create_resolver(&exec_ctx, "dns:test");
   gpr_event ev1;
   gpr_event_init(&ev1);
-  grpc_resolver_next(&exec_ctx, resolver, &result,
-                     grpc_closure_create(on_done, &ev1));
+  grpc_resolver_next(
+      &exec_ctx, resolver, &result,
+      grpc_closure_create(on_done, &ev1, grpc_schedule_on_exec_ctx));
   grpc_exec_ctx_flush(&exec_ctx);
   GPR_ASSERT(wait_loop(5, &ev1));
   GPR_ASSERT(result == NULL);
 
   gpr_event ev2;
   gpr_event_init(&ev2);
-  grpc_resolver_next(&exec_ctx, resolver, &result,
-                     grpc_closure_create(on_done, &ev2));
+  grpc_resolver_next(
+      &exec_ctx, resolver, &result,
+      grpc_closure_create(on_done, &ev2, grpc_schedule_on_exec_ctx));
   grpc_exec_ctx_flush(&exec_ctx);
   GPR_ASSERT(wait_loop(30, &ev2));
   GPR_ASSERT(result != NULL);
 
-  grpc_channel_args_destroy(result);
+  grpc_channel_args_destroy(&exec_ctx, result);
   GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test");
   grpc_exec_ctx_finish(&exec_ctx);
 
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.c b/test/core/client_channel/resolvers/dns_resolver_test.c
index 41a9125..5603a57 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.c
+++ b/test/core/client_channel/resolvers/dns_resolver_test.c
@@ -48,7 +48,7 @@
   GPR_ASSERT(uri);
   memset(&args, 0, sizeof(args));
   args.uri = uri;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
   GPR_ASSERT(resolver != NULL);
   GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test_succeeds");
   grpc_uri_destroy(uri);
@@ -65,7 +65,7 @@
   GPR_ASSERT(uri);
   memset(&args, 0, sizeof(args));
   args.uri = uri;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
   GPR_ASSERT(resolver == NULL);
   grpc_uri_destroy(uri);
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.c b/test/core/client_channel/resolvers/sockaddr_resolver_test.c
index ebf311a..10df785 100644
--- a/test/core/client_channel/resolvers/sockaddr_resolver_test.c
+++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.c
@@ -49,12 +49,7 @@
 
 void on_resolution_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
   on_resolution_arg *res = arg;
-  const grpc_arg *channel_arg =
-      grpc_channel_args_find(res->resolver_result, GRPC_ARG_SERVER_NAME);
-  GPR_ASSERT(channel_arg != NULL);
-  GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-  GPR_ASSERT(strcmp(res->expected_server_name, channel_arg->value.string) == 0);
-  grpc_channel_args_destroy(res->resolver_result);
+  grpc_channel_args_destroy(exec_ctx, res->resolver_result);
 }
 
 static void test_succeeds(grpc_resolver_factory *factory, const char *string) {
@@ -67,14 +62,14 @@
   GPR_ASSERT(uri);
   memset(&args, 0, sizeof(args));
   args.uri = uri;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
   GPR_ASSERT(resolver != NULL);
 
   on_resolution_arg on_res_arg;
   memset(&on_res_arg, 0, sizeof(on_res_arg));
   on_res_arg.expected_server_name = uri->path;
-  grpc_closure *on_resolution =
-      grpc_closure_create(on_resolution_cb, &on_res_arg);
+  grpc_closure *on_resolution = grpc_closure_create(
+      on_resolution_cb, &on_res_arg, grpc_schedule_on_exec_ctx);
 
   grpc_resolver_next(&exec_ctx, resolver, &on_res_arg.resolver_result,
                      on_resolution);
@@ -93,7 +88,7 @@
   GPR_ASSERT(uri);
   memset(&args, 0, sizeof(args));
   args.uri = uri;
-  resolver = grpc_resolver_factory_create_resolver(factory, &args);
+  resolver = grpc_resolver_factory_create_resolver(&exec_ctx, factory, &args);
   GPR_ASSERT(resolver == NULL);
   grpc_uri_destroy(uri);
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/client_channel/set_initial_connect_string_test.c b/test/core/client_channel/set_initial_connect_string_test.c
index 11e5743..b78ba98 100644
--- a/test/core/client_channel/set_initial_connect_string_test.c
+++ b/test/core/client_channel/set_initial_connect_string_test.c
@@ -94,7 +94,7 @@
                        grpc_tcp_server_acceptor *acceptor) {
   gpr_free(acceptor);
   test_tcp_server *server = arg;
-  grpc_closure_init(&on_read, handle_read, NULL);
+  grpc_closure_init(&on_read, handle_read, NULL, grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&state.incoming_buffer);
   grpc_slice_buffer_init(&state.temp_incoming_buffer);
   state.tcp = tcp;
@@ -158,7 +158,7 @@
   grpc_event ev;
   grpc_slice_buffer_destroy(&state.incoming_buffer);
   grpc_slice_buffer_destroy(&state.temp_incoming_buffer);
-  grpc_channel_credentials_unref(state.creds);
+  grpc_channel_credentials_release(state.creds);
   grpc_call_destroy(state.call);
   grpc_completion_queue_shutdown(state.cq);
   do {
diff --git a/test/core/compression/algorithm_test.c b/test/core/compression/algorithm_test.c
index bdee748..ff17667 100644
--- a/test/core/compression/algorithm_test.c
+++ b/test/core/compression/algorithm_test.c
@@ -53,6 +53,7 @@
     grpc_compression_algorithm parsed;
     grpc_mdstr *mdstr;
     grpc_mdelem *mdelem;
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     GPR_ASSERT(
         grpc_compression_algorithm_name((grpc_compression_algorithm)i, &name));
     GPR_ASSERT(grpc_compression_algorithm_parse(name, strlen(name), &parsed));
@@ -63,8 +64,9 @@
     mdelem = grpc_compression_encoding_mdelem(parsed);
     GPR_ASSERT(mdelem->value == mdstr);
     GPR_ASSERT(mdelem->key == GRPC_MDSTR_GRPC_ENCODING);
-    GRPC_MDSTR_UNREF(mdstr);
-    GRPC_MDELEM_UNREF(mdelem);
+    GRPC_MDSTR_UNREF(&exec_ctx, mdstr);
+    GRPC_MDELEM_UNREF(&exec_ctx, mdelem);
+    grpc_exec_ctx_finish(&exec_ctx);
   }
 
   /* test failure */
@@ -73,6 +75,7 @@
 }
 
 static void test_algorithm_failure(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_mdstr *mdstr;
 
   gpr_log(GPR_DEBUG, "test_algorithm_failure");
@@ -88,7 +91,8 @@
              NULL);
   GPR_ASSERT(grpc_compression_algorithm_mdstr(GRPC_COMPRESS_ALGORITHMS_COUNT +
                                               1) == NULL);
-  GRPC_MDSTR_UNREF(mdstr);
+  GRPC_MDSTR_UNREF(&exec_ctx, mdstr);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/compression/message_compress_test.c b/test/core/compression/message_compress_test.c
index fc53cd9..2432ca7 100644
--- a/test/core/compression/message_compress_test.c
+++ b/test/core/compression/message_compress_test.c
@@ -40,6 +40,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/support/murmur_hash.h"
 #include "test/core/util/slice_splitter.h"
 #include "test/core/util/test_config.h"
@@ -82,7 +83,12 @@
 
   grpc_split_slices_to_buffer(uncompressed_split_mode, &value, 1, &input);
 
-  was_compressed = grpc_msg_compress(algorithm, &input, &compressed_raw);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    was_compressed =
+        grpc_msg_compress(&exec_ctx, algorithm, &input, &compressed_raw);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   GPR_ASSERT(input.count > 0);
 
   switch (compress_result_check) {
@@ -99,8 +105,13 @@
 
   grpc_split_slice_buffer(compressed_split_mode, &compressed_raw, &compressed);
 
-  GPR_ASSERT(grpc_msg_decompress(
-      was_compressed ? algorithm : GRPC_COMPRESS_NONE, &compressed, &output));
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    GPR_ASSERT(grpc_msg_decompress(
+        &exec_ctx, was_compressed ? algorithm : GRPC_COMPRESS_NONE, &compressed,
+        &output));
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   final = grpc_slice_merge(output.slices, output.count);
   GPR_ASSERT(0 == grpc_slice_cmp(value, final));
@@ -160,7 +171,9 @@
 
   for (i = 0; i < GRPC_COMPRESS_ALGORITHMS_COUNT; i++) {
     if (i == GRPC_COMPRESS_NONE) continue;
-    GPR_ASSERT(0 == grpc_msg_compress(i, &input, &output));
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    GPR_ASSERT(0 == grpc_msg_compress(&exec_ctx, i, &input, &output));
+    grpc_exec_ctx_finish(&exec_ctx);
     GPR_ASSERT(1 == output.count);
   }
 
@@ -180,8 +193,9 @@
   grpc_slice_buffer_init(&output);
   grpc_slice_buffer_add(&input, create_test_value(ONE_MB_A));
 
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   /* compress it */
-  grpc_msg_compress(GRPC_COMPRESS_GZIP, &input, &corrupted);
+  grpc_msg_compress(&exec_ctx, GRPC_COMPRESS_GZIP, &input, &corrupted);
   /* corrupt the output by smashing the CRC */
   GPR_ASSERT(corrupted.count > 1);
   GPR_ASSERT(GRPC_SLICE_LENGTH(corrupted.slices[1]) > 8);
@@ -189,7 +203,9 @@
   memcpy(GRPC_SLICE_START_PTR(corrupted.slices[1]) + idx, &bad, 4);
 
   /* try (and fail) to decompress the corrupted compresed buffer */
-  GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_GZIP, &corrupted, &output));
+  GPR_ASSERT(0 == grpc_msg_decompress(&exec_ctx, GRPC_COMPRESS_GZIP, &corrupted,
+                                      &output));
+  grpc_exec_ctx_finish(&exec_ctx);
 
   grpc_slice_buffer_destroy(&input);
   grpc_slice_buffer_destroy(&corrupted);
@@ -208,7 +224,10 @@
                   "\x78\xda\x63\x60\x60\x60\x00\x00\x00\x04\x00\x01\x99", 13));
 
   /* try (and fail) to decompress the invalid compresed buffer */
-  GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_DEFLATE, &input, &output));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GPR_ASSERT(0 == grpc_msg_decompress(&exec_ctx, GRPC_COMPRESS_DEFLATE, &input,
+                                      &output));
+  grpc_exec_ctx_finish(&exec_ctx);
 
   grpc_slice_buffer_destroy(&input);
   grpc_slice_buffer_destroy(&output);
@@ -224,7 +243,10 @@
                         grpc_slice_from_copied_buffer("\x78\xda\xff\xff", 4));
 
   /* try (and fail) to decompress the invalid compresed buffer */
-  GPR_ASSERT(0 == grpc_msg_decompress(GRPC_COMPRESS_DEFLATE, &input, &output));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GPR_ASSERT(0 == grpc_msg_decompress(&exec_ctx, GRPC_COMPRESS_DEFLATE, &input,
+                                      &output));
+  grpc_exec_ctx_finish(&exec_ctx);
 
   grpc_slice_buffer_destroy(&input);
   grpc_slice_buffer_destroy(&output);
@@ -239,13 +261,16 @@
   grpc_slice_buffer_init(&output);
   grpc_slice_buffer_add(
       &input, grpc_slice_from_copied_string("Never gonna give you up"));
-  was_compressed =
-      grpc_msg_compress(GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output);
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  was_compressed = grpc_msg_compress(&exec_ctx, GRPC_COMPRESS_ALGORITHMS_COUNT,
+                                     &input, &output);
   GPR_ASSERT(0 == was_compressed);
 
-  was_compressed =
-      grpc_msg_compress(GRPC_COMPRESS_ALGORITHMS_COUNT + 123, &input, &output);
+  was_compressed = grpc_msg_compress(
+      &exec_ctx, GRPC_COMPRESS_ALGORITHMS_COUNT + 123, &input, &output);
   GPR_ASSERT(0 == was_compressed);
+  grpc_exec_ctx_finish(&exec_ctx);
 
   grpc_slice_buffer_destroy(&input);
   grpc_slice_buffer_destroy(&output);
@@ -261,13 +286,15 @@
   grpc_slice_buffer_add(&input,
                         grpc_slice_from_copied_string(
                             "I'm not really compressed but it doesn't matter"));
-  was_decompressed =
-      grpc_msg_decompress(GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  was_decompressed = grpc_msg_decompress(
+      &exec_ctx, GRPC_COMPRESS_ALGORITHMS_COUNT, &input, &output);
   GPR_ASSERT(0 == was_decompressed);
 
-  was_decompressed = grpc_msg_decompress(GRPC_COMPRESS_ALGORITHMS_COUNT + 123,
-                                         &input, &output);
+  was_decompressed = grpc_msg_decompress(
+      &exec_ctx, GRPC_COMPRESS_ALGORITHMS_COUNT + 123, &input, &output);
   GPR_ASSERT(0 == was_decompressed);
+  grpc_exec_ctx_finish(&exec_ctx);
 
   grpc_slice_buffer_destroy(&input);
   grpc_slice_buffer_destroy(&output);
diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD
new file mode 100644
index 0000000..681cea1
--- /dev/null
+++ b/test/core/end2end/BUILD
@@ -0,0 +1,78 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+load(":generate_tests.bzl", "grpc_end2end_tests")
+
+cc_library(
+  name = 'cq_verifier',
+  srcs = ['cq_verifier.c'],
+  hdrs = ['cq_verifier.h'],
+  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util'],
+  copts = ['-std=c99'],
+  visibility = ["//test:__subpackages__"],
+)
+
+cc_library(
+  name = 'ssl_test_data',
+  visibility = ["//test:__subpackages__"],
+  hdrs = ['data/ssl_test_data.h'],
+  copts = ['-std=c99'],
+  srcs = [
+    "data/client_certs.c",
+    "data/server1_cert.c",
+    "data/server1_key.c",
+    "data/test_root_cert.c",
+  ]
+)
+
+cc_library(
+  name = 'fake_resolver',
+  hdrs = ['fake_resolver.h'],
+  srcs = ['fake_resolver.c'],
+  copts = ['-std=c99'],
+  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+)
+
+cc_library(
+  name = 'http_proxy',
+  hdrs = ['fixtures/http_proxy.h'],
+  srcs = ['fixtures/http_proxy.c'],
+  copts = ['-std=c99'],
+  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+)
+
+cc_library(
+  name = 'proxy',
+  hdrs = ['fixtures/proxy.h'],
+  srcs = ['fixtures/proxy.c'],
+  copts = ['-std=c99'],
+  deps = ['//:gpr', '//:grpc', '//test/core/util:grpc_test_util']
+)
+
+grpc_end2end_tests()
diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c
index 3046855..a052016 100644
--- a/test/core/end2end/bad_server_response_test.c
+++ b/test/core/end2end/bad_server_response_test.c
@@ -47,6 +47,7 @@
 #include <grpc/support/thd.h>
 
 #include "src/core/lib/iomgr/sockaddr.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
@@ -147,8 +148,8 @@
                        grpc_tcp_server_acceptor *acceptor) {
   gpr_free(acceptor);
   test_tcp_server *server = arg;
-  grpc_closure_init(&on_read, handle_read, NULL);
-  grpc_closure_init(&on_write, done_write, NULL);
+  grpc_closure_init(&on_read, handle_read, NULL, grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&on_write, done_write, NULL, grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&state.temp_incoming_buffer);
   grpc_slice_buffer_init(&state.outgoing_buffer);
   state.tcp = tcp;
@@ -227,10 +228,10 @@
   cq_verifier_destroy(cqv);
 }
 
-static void cleanup_rpc(void) {
+static void cleanup_rpc(grpc_exec_ctx *exec_ctx) {
   grpc_event ev;
-  grpc_slice_buffer_destroy(&state.temp_incoming_buffer);
-  grpc_slice_buffer_destroy(&state.outgoing_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &state.temp_incoming_buffer);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &state.outgoing_buffer);
   grpc_call_destroy(state.call);
   grpc_completion_queue_shutdown(state.cq);
   do {
@@ -299,8 +300,8 @@
   /* clean up */
   grpc_endpoint_shutdown(&exec_ctx, state.tcp);
   grpc_endpoint_destroy(&exec_ctx, state.tcp);
+  cleanup_rpc(&exec_ctx);
   grpc_exec_ctx_finish(&exec_ctx);
-  cleanup_rpc();
   test_tcp_server_destroy(&test_server);
 
   grpc_shutdown();
diff --git a/test/core/end2end/connection_refused_test.c b/test/core/end2end/connection_refused_test.c
index 728d6dc..4430804 100644
--- a/test/core/end2end/connection_refused_test.c
+++ b/test/core/end2end/connection_refused_test.c
@@ -145,7 +145,11 @@
   gpr_free(details);
   grpc_metadata_array_destroy(&trailing_metadata_recv);
 
-  if (args != NULL) grpc_channel_args_destroy(args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    if (args != NULL) grpc_channel_args_destroy(&exec_ctx, args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   grpc_shutdown();
 }
diff --git a/src/python/grpcio_health_checking/grpc/__init__.py b/test/core/end2end/end2end_test.sh
old mode 100644
new mode 100755
similarity index 93%
copy from src/python/grpcio_health_checking/grpc/__init__.py
copy to test/core/end2end/end2end_test.sh
index fcc7048..f2309ac
--- a/src/python/grpcio_health_checking/grpc/__init__.py
+++ b/test/core/end2end/end2end_test.sh
@@ -1,4 +1,8 @@
-# Copyright 2015, Google Inc.
+#!/bin/sh
+
+# Test runner for end2end tests from bazel
+
+# Copyright 2017, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -26,5 +30,4 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-__import__('pkg_resources').declare_namespace(__name__)
+$1 $2
diff --git a/test/core/end2end/fake_resolver.c b/test/core/end2end/fake_resolver.c
index 865b55d..966642f 100644
--- a/test/core/end2end/fake_resolver.c
+++ b/test/core/end2end/fake_resolver.c
@@ -48,6 +48,7 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
@@ -76,8 +77,8 @@
 static void fake_resolver_destroy(grpc_exec_ctx* exec_ctx, grpc_resolver* gr) {
   fake_resolver* r = (fake_resolver*)gr;
   gpr_mu_destroy(&r->mu);
-  grpc_channel_args_destroy(r->channel_args);
-  grpc_lb_addresses_destroy(r->addresses);
+  grpc_channel_args_destroy(exec_ctx, r->channel_args);
+  grpc_lb_addresses_destroy(exec_ctx, r->addresses);
   gpr_free(r);
 }
 
@@ -87,7 +88,7 @@
   gpr_mu_lock(&r->mu);
   if (r->next_completion != NULL) {
     *r->target_result = NULL;
-    grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
   }
   gpr_mu_unlock(&r->mu);
@@ -100,7 +101,7 @@
     grpc_arg arg = grpc_lb_addresses_create_channel_arg(r->addresses);
     *r->target_result =
         grpc_channel_args_copy_and_add(r->channel_args, &arg, 1);
-    grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE);
     r->next_completion = NULL;
   }
 }
@@ -140,7 +141,8 @@
 
 static void do_nothing(void* ignored) {}
 
-static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
+static grpc_resolver* fake_resolver_create(grpc_exec_ctx* exec_ctx,
+                                           grpc_resolver_factory* factory,
                                            grpc_resolver_args* args) {
   if (0 != strcmp(args->uri->authority, "")) {
     gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
@@ -172,21 +174,16 @@
     addresses->addresses[i].is_balancer = lb_enabled;
     if (errors_found) break;
   }
-  grpc_slice_buffer_destroy(&path_parts);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &path_parts);
   grpc_slice_unref(path_slice);
   if (errors_found) {
-    grpc_lb_addresses_destroy(addresses);
+    grpc_lb_addresses_destroy(exec_ctx, addresses);
     return NULL;
   }
   // Instantiate resolver.
   fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
   memset(r, 0, sizeof(*r));
-  grpc_arg server_name_arg;
-  server_name_arg.type = GRPC_ARG_STRING;
-  server_name_arg.key = GRPC_ARG_SERVER_NAME;
-  server_name_arg.value.string = args->uri->path;
-  r->channel_args =
-      grpc_channel_args_copy_and_add(args->args, &server_name_arg, 1);
+  r->channel_args = grpc_channel_args_copy(args->args);
   r->addresses = addresses;
   gpr_mu_init(&r->mu);
   grpc_resolver_init(&r->base, &fake_resolver_vtable);
diff --git a/test/core/end2end/fixtures/h2_census.c b/test/core/end2end/fixtures/h2_census.c
index c52d766..8e60123 100644
--- a/test/core/end2end/fixtures/h2_census.c
+++ b/test/core/end2end/fixtures/h2_census.c
@@ -85,7 +85,11 @@
   client_args = grpc_channel_args_copy_and_add(client_args, &arg, 1);
   f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
   GPR_ASSERT(f->client);
-  grpc_channel_args_destroy(client_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, client_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
@@ -97,7 +101,11 @@
   }
   server_args = grpc_channel_args_copy_and_add(server_args, &arg, 1);
   f->server = grpc_server_create(server_args, NULL);
-  grpc_channel_args_destroy(server_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
diff --git a/test/core/end2end/fixtures/h2_compress.c b/test/core/end2end/fixtures/h2_compress.c
index fedd2eb..c01e456 100644
--- a/test/core/end2end/fixtures/h2_compress.c
+++ b/test/core/end2end/fixtures/h2_compress.c
@@ -78,7 +78,9 @@
                                               grpc_channel_args *client_args) {
   fullstack_compression_fixture_data *ffd = f->fixture_data;
   if (ffd->client_args_compression != NULL) {
-    grpc_channel_args_destroy(ffd->client_args_compression);
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, ffd->client_args_compression);
+    grpc_exec_ctx_finish(&exec_ctx);
   }
   ffd->client_args_compression = grpc_channel_args_set_compression_algorithm(
       client_args, GRPC_COMPRESS_GZIP);
@@ -90,7 +92,9 @@
                                               grpc_channel_args *server_args) {
   fullstack_compression_fixture_data *ffd = f->fixture_data;
   if (ffd->server_args_compression != NULL) {
-    grpc_channel_args_destroy(ffd->server_args_compression);
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, ffd->server_args_compression);
+    grpc_exec_ctx_finish(&exec_ctx);
   }
   ffd->server_args_compression = grpc_channel_args_set_compression_algorithm(
       server_args, GRPC_COMPRESS_GZIP);
@@ -104,11 +108,13 @@
 }
 
 void chttp2_tear_down_fullstack_compression(grpc_end2end_test_fixture *f) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   fullstack_compression_fixture_data *ffd = f->fixture_data;
-  grpc_channel_args_destroy(ffd->client_args_compression);
-  grpc_channel_args_destroy(ffd->server_args_compression);
+  grpc_channel_args_destroy(&exec_ctx, ffd->client_args_compression);
+  grpc_channel_args_destroy(&exec_ctx, ffd->server_args_compression);
   gpr_free(ffd->localaddr);
   gpr_free(ffd);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 /* All test configurations */
diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c
index 7a76489..38321f3 100644
--- a/test/core/end2end/fixtures/h2_load_reporting.c
+++ b/test/core/end2end/fixtures/h2_load_reporting.c
@@ -88,7 +88,11 @@
   }
   server_args = grpc_channel_args_copy_and_add(server_args, &arg, 1);
   f->server = grpc_server_create(server_args, NULL);
-  grpc_channel_args_destroy(server_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr));
   grpc_server_start(f->server);
diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c
index 6122f4f..83f759c 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -163,7 +163,11 @@
   grpc_channel_args *new_client_args =
       grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_oauth2_creds);
-  grpc_channel_args_destroy(new_client_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, new_client_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   grpc_channel_credentials_release(ssl_creds);
   grpc_call_credentials_release(oauth2_creds);
 }
diff --git a/test/core/end2end/fixtures/h2_ssl.c b/test/core/end2end/fixtures/h2_ssl.c
index bbd522c..cf44cd0 100644
--- a/test/core/end2end/fixtures/h2_ssl.c
+++ b/test/core/end2end/fixtures/h2_ssl.c
@@ -118,7 +118,11 @@
   grpc_channel_args *new_client_args =
       grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);
-  grpc_channel_args_destroy(new_client_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, new_client_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 static int fail_server_auth_check(grpc_channel_args *server_args) {
diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c
index e39cb49..ae49cc8 100644
--- a/test/core/end2end/fixtures/h2_ssl_cert.c
+++ b/test/core/end2end/fixtures/h2_ssl_cert.c
@@ -186,7 +186,11 @@
     grpc_channel_args *new_client_args =                                     \
         grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);  \
     chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);      \
-    grpc_channel_args_destroy(new_client_args);                              \
+    {                                                                        \
+      grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;                           \
+      grpc_channel_args_destroy(&exec_ctx, new_client_args);                 \
+      grpc_exec_ctx_finish(&exec_ctx);                                       \
+    }                                                                        \
   }
 
 CLIENT_INIT(NONE)
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.c b/test/core/end2end/fixtures/h2_ssl_proxy.c
index 27cf3eb..740b075 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.c
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.c
@@ -79,7 +79,11 @@
   channel =
       grpc_secure_channel_create(ssl_creds, target, new_client_args, NULL);
   grpc_channel_credentials_release(ssl_creds);
-  grpc_channel_args_destroy(new_client_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, new_client_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   return channel;
 }
 
@@ -151,7 +155,11 @@
   grpc_channel_args *new_client_args =
       grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_creds);
-  grpc_channel_args_destroy(new_client_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, new_client_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 static int fail_server_auth_check(grpc_channel_args *server_args) {
diff --git a/test/core/end2end/fixtures/http_proxy.c b/test/core/end2end/fixtures/http_proxy.c
index 80865fc..b62082c 100644
--- a/test/core/end2end/fixtures/http_proxy.c
+++ b/test/core/end2end/fixtures/http_proxy.c
@@ -59,6 +59,7 @@
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/iomgr/tcp_server.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/port.h"
 
 struct grpc_end2end_http_proxy {
@@ -110,12 +111,14 @@
     if (conn->server_endpoint != NULL)
       grpc_endpoint_destroy(exec_ctx, conn->server_endpoint);
     grpc_pollset_set_destroy(conn->pollset_set);
-    grpc_slice_buffer_destroy(&conn->client_read_buffer);
-    grpc_slice_buffer_destroy(&conn->client_deferred_write_buffer);
-    grpc_slice_buffer_destroy(&conn->client_write_buffer);
-    grpc_slice_buffer_destroy(&conn->server_read_buffer);
-    grpc_slice_buffer_destroy(&conn->server_deferred_write_buffer);
-    grpc_slice_buffer_destroy(&conn->server_write_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_read_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx,
+                                       &conn->client_deferred_write_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &conn->client_write_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &conn->server_read_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx,
+                                       &conn->server_deferred_write_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &conn->server_write_buffer);
     grpc_http_parser_destroy(&conn->http_parser);
     grpc_http_request_destroy(&conn->http_request);
     gpr_free(conn);
@@ -376,15 +379,20 @@
   gpr_ref_init(&conn->refcount, 1);
   conn->pollset_set = grpc_pollset_set_create();
   grpc_pollset_set_add_pollset(exec_ctx, conn->pollset_set, proxy->pollset);
-  grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn);
-  grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done,
-                    conn);
-  grpc_closure_init(&conn->on_write_response_done, on_write_response_done,
-                    conn);
-  grpc_closure_init(&conn->on_client_read_done, on_client_read_done, conn);
-  grpc_closure_init(&conn->on_client_write_done, on_client_write_done, conn);
-  grpc_closure_init(&conn->on_server_read_done, on_server_read_done, conn);
-  grpc_closure_init(&conn->on_server_write_done, on_server_write_done, conn);
+  grpc_closure_init(&conn->on_read_request_done, on_read_request_done, conn,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&conn->on_server_connect_done, on_server_connect_done, conn,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&conn->on_write_response_done, on_write_response_done, conn,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&conn->on_client_read_done, on_client_read_done, conn,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&conn->on_client_write_done, on_client_write_done, conn,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&conn->on_server_read_done, on_server_read_done, conn,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&conn->on_server_write_done, on_server_write_done, conn,
+                    grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&conn->client_read_buffer);
   grpc_slice_buffer_init(&conn->client_deferred_write_buffer);
   grpc_slice_buffer_init(&conn->client_write_buffer);
@@ -469,9 +477,10 @@
   grpc_tcp_server_shutdown_listeners(&exec_ctx, proxy->server);
   grpc_tcp_server_unref(&exec_ctx, proxy->server);
   gpr_free(proxy->proxy_name);
-  grpc_channel_args_destroy(proxy->channel_args);
+  grpc_channel_args_destroy(&exec_ctx, proxy->channel_args);
   grpc_closure destroyed;
-  grpc_closure_init(&destroyed, destroy_pollset, proxy->pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, proxy->pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, proxy->pollset, &destroyed);
   gpr_free(proxy);
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/core/end2end/fuzzers/BUILD
old mode 100755
new mode 100644
similarity index 68%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/core/end2end/fuzzers/BUILD
index 7438713..2adda56
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/core/end2end/fuzzers/BUILD
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,28 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cd $(dirname $0)/../..
+grpc_fuzzer(
+  name = "api_fuzzer",
+  srcs = ["api_fuzzer.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util", "//test/core/end2end:ssl_test_data"],
+  corpus = "api_fuzzer_corpus",
+  copts = ["-std=c99"],
+)
 
-make grpc_csharp_ext
+grpc_fuzzer(
+  name = "client_fuzzer",
+  srcs = ["client_fuzzer.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "client_fuzzer_corpus",
+  copts = ["-std=c99"],
+)
 
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
+grpc_fuzzer(
+  name = "server_fuzzer",
+  srcs = ["server_fuzzer.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "server_fuzzer_corpus",
+  copts = ["-std=c99"],
+)
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index 19ac6ce..200a518 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -349,11 +349,11 @@
     addrs->addrs = gpr_malloc(sizeof(*addrs->addrs));
     addrs->addrs[0].len = 0;
     *r->addrs = addrs;
-    grpc_exec_ctx_sched(exec_ctx, r->on_done, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, r->on_done, GRPC_ERROR_NONE);
   } else {
-    grpc_exec_ctx_sched(
+    grpc_closure_sched(
         exec_ctx, r->on_done,
-        GRPC_ERROR_CREATE_REFERENCING("Resolution failed", &error, 1), NULL);
+        GRPC_ERROR_CREATE_REFERENCING("Resolution failed", &error, 1));
   }
 
   gpr_free(r->addr);
@@ -361,16 +361,19 @@
 }
 
 void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
-                        const char *default_port, grpc_closure *on_done,
+                        const char *default_port,
+                        grpc_pollset_set *interested_parties,
+                        grpc_closure *on_done,
                         grpc_resolved_addresses **addresses) {
   addr_req *r = gpr_malloc(sizeof(*r));
   r->addr = gpr_strdup(addr);
   r->on_done = on_done;
   r->addrs = addresses;
-  grpc_timer_init(exec_ctx, &r->timer,
-                  gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                               gpr_time_from_seconds(1, GPR_TIMESPAN)),
-                  finish_resolve, r, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(
+      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),
+      grpc_closure_create(finish_resolve, r, grpc_schedule_on_exec_ctx),
+      gpr_now(GPR_CLOCK_MONOTONIC));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -396,7 +399,7 @@
   future_connect *fc = arg;
   if (error != GRPC_ERROR_NONE) {
     *fc->ep = NULL;
-    grpc_exec_ctx_sched(exec_ctx, fc->closure, GRPC_ERROR_REF(error), NULL);
+    grpc_closure_sched(exec_ctx, fc->closure, GRPC_ERROR_REF(error));
   } else if (g_server != NULL) {
     grpc_endpoint *client;
     grpc_endpoint *server;
@@ -408,7 +411,7 @@
     grpc_server_setup_transport(exec_ctx, g_server, transport, NULL, NULL);
     grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL);
 
-    grpc_exec_ctx_sched(exec_ctx, fc->closure, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, fc->closure, GRPC_ERROR_NONE);
   } else {
     sched_connect(exec_ctx, fc->closure, fc->ep, fc->deadline);
   }
@@ -419,8 +422,8 @@
                           grpc_endpoint **ep, gpr_timespec deadline) {
   if (gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) < 0) {
     *ep = NULL;
-    grpc_exec_ctx_sched(exec_ctx, closure,
-                        GRPC_ERROR_CREATE("Connect deadline exceeded"), NULL);
+    grpc_closure_sched(exec_ctx, closure,
+                       GRPC_ERROR_CREATE("Connect deadline exceeded"));
     return;
   }
 
@@ -428,10 +431,11 @@
   fc->closure = closure;
   fc->ep = ep;
   fc->deadline = deadline;
-  grpc_timer_init(exec_ctx, &fc->timer,
-                  gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                               gpr_time_from_millis(1, GPR_TIMESPAN)),
-                  do_connect, fc, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(
+      exec_ctx, &fc->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                         gpr_time_from_millis(1, GPR_TIMESPAN)),
+      grpc_closure_create(do_connect, fc, grpc_schedule_on_exec_ctx),
+      gpr_now(GPR_CLOCK_MONOTONIC));
 }
 
 static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx,
@@ -744,7 +748,11 @@
           grpc_channel_args *args = read_args(&inp);
           g_channel = grpc_insecure_channel_create(target_uri, args, NULL);
           GPR_ASSERT(g_channel != NULL);
-          grpc_channel_args_destroy(args);
+          {
+            grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+            grpc_channel_args_destroy(&exec_ctx, args);
+            grpc_exec_ctx_finish(&exec_ctx);
+          }
           gpr_free(target_uri);
           gpr_free(target);
         } else {
@@ -768,7 +776,11 @@
           grpc_channel_args *args = read_args(&inp);
           g_server = grpc_server_create(args, NULL);
           GPR_ASSERT(g_server != NULL);
-          grpc_channel_args_destroy(args);
+          {
+            grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+            grpc_channel_args_destroy(&exec_ctx, args);
+            grpc_exec_ctx_finish(&exec_ctx);
+          }
           grpc_server_register_completion_queue(g_server, cq, NULL);
           grpc_server_start(g_server);
           server_shutdown = false;
@@ -1104,7 +1116,11 @@
           grpc_channel_credentials *creds = read_channel_creds(&inp);
           g_channel = grpc_secure_channel_create(creds, target_uri, args, NULL);
           GPR_ASSERT(g_channel != NULL);
-          grpc_channel_args_destroy(args);
+          {
+            grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+            grpc_channel_args_destroy(&exec_ctx, args);
+            grpc_exec_ctx_finish(&exec_ctx);
+          }
           gpr_free(target_uri);
           gpr_free(target);
           grpc_channel_credentials_release(creds);
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/08455b3ef9d516deb8155d8db7d51c43ce0ff07a b/test/core/end2end/fuzzers/api_fuzzer_corpus/08455b3ef9d516deb8155d8db7d51c43ce0ff07a
new file mode 100644
index 0000000..4b698ba
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/08455b3ef9d516deb8155d8db7d51c43ce0ff07a
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/0d19e60f4eb1b729e272dd5dec68e8b67f03a5f4 b/test/core/end2end/fuzzers/api_fuzzer_corpus/0d19e60f4eb1b729e272dd5dec68e8b67f03a5f4
new file mode 100644
index 0000000..2889e70
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/0d19e60f4eb1b729e272dd5dec68e8b67f03a5f4
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/14064ac4844c709b247a4345a92d8be9766785c4 b/test/core/end2end/fuzzers/api_fuzzer_corpus/14064ac4844c709b247a4345a92d8be9766785c4
new file mode 100644
index 0000000..fa731d4
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/14064ac4844c709b247a4345a92d8be9766785c4
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/1901234bd7c9cb6ee19ff8b17179c481bdc7c5f2 b/test/core/end2end/fuzzers/api_fuzzer_corpus/1901234bd7c9cb6ee19ff8b17179c481bdc7c5f2
new file mode 100644
index 0000000..ef09a0e
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/1901234bd7c9cb6ee19ff8b17179c481bdc7c5f2
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/20ff1f8d5d34cb01d58aa334dc46a6644e6e1d12 b/test/core/end2end/fuzzers/api_fuzzer_corpus/20ff1f8d5d34cb01d58aa334dc46a6644e6e1d12
new file mode 100644
index 0000000..fc747d4
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/20ff1f8d5d34cb01d58aa334dc46a6644e6e1d12
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/2378c3f1206f20711468391ce739116ffe58374b b/test/core/end2end/fuzzers/api_fuzzer_corpus/2378c3f1206f20711468391ce739116ffe58374b
new file mode 100644
index 0000000..ca3ce31
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/2378c3f1206f20711468391ce739116ffe58374b
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/40640a91fda4e4e42d3063a28b9ffbba1b8c3701 b/test/core/end2end/fuzzers/api_fuzzer_corpus/40640a91fda4e4e42d3063a28b9ffbba1b8c3701
new file mode 100644
index 0000000..f11821a
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/40640a91fda4e4e42d3063a28b9ffbba1b8c3701
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/49f564289c79de9e0342f8b0821a167bc8c5ec00 b/test/core/end2end/fuzzers/api_fuzzer_corpus/49f564289c79de9e0342f8b0821a167bc8c5ec00
new file mode 100644
index 0000000..c846377
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/49f564289c79de9e0342f8b0821a167bc8c5ec00
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/507865c4a5ce880b80400d93fa85def2682581cb b/test/core/end2end/fuzzers/api_fuzzer_corpus/507865c4a5ce880b80400d93fa85def2682581cb
new file mode 100644
index 0000000..c4473ea
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/507865c4a5ce880b80400d93fa85def2682581cb
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/5f2fdb01d8ff632803ca2b732a7c088c6843d7d3 b/test/core/end2end/fuzzers/api_fuzzer_corpus/5f2fdb01d8ff632803ca2b732a7c088c6843d7d3
new file mode 100644
index 0000000..b91a052
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/5f2fdb01d8ff632803ca2b732a7c088c6843d7d3
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/61de97a9d6c4b082602c02277d8d763921f5f95b b/test/core/end2end/fuzzers/api_fuzzer_corpus/61de97a9d6c4b082602c02277d8d763921f5f95b
new file mode 100644
index 0000000..a24008b
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/61de97a9d6c4b082602c02277d8d763921f5f95b
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/62b039b8a318cc08471f13629da08c68c414d8e7 b/test/core/end2end/fuzzers/api_fuzzer_corpus/62b039b8a318cc08471f13629da08c68c414d8e7
new file mode 100644
index 0000000..e5e218a
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/62b039b8a318cc08471f13629da08c68c414d8e7
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/641739453f7d4d3b55a1c7b79bed7da6dfd62ae0 b/test/core/end2end/fuzzers/api_fuzzer_corpus/641739453f7d4d3b55a1c7b79bed7da6dfd62ae0
new file mode 100644
index 0000000..9dcc5c5
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/641739453f7d4d3b55a1c7b79bed7da6dfd62ae0
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/6589505362ffb5164a3c7cb1b9feadcddfba44e9 b/test/core/end2end/fuzzers/api_fuzzer_corpus/6589505362ffb5164a3c7cb1b9feadcddfba44e9
new file mode 100644
index 0000000..10625da
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/6589505362ffb5164a3c7cb1b9feadcddfba44e9
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/724f5400f19e5a0be97022341c39eeaaaffeb390 b/test/core/end2end/fuzzers/api_fuzzer_corpus/724f5400f19e5a0be97022341c39eeaaaffeb390
new file mode 100644
index 0000000..1dbc538
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/724f5400f19e5a0be97022341c39eeaaaffeb390
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/7254b9ff59ab3fcf345effdabbc25ebd2e907b23 b/test/core/end2end/fuzzers/api_fuzzer_corpus/7254b9ff59ab3fcf345effdabbc25ebd2e907b23
new file mode 100644
index 0000000..92371e0
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/7254b9ff59ab3fcf345effdabbc25ebd2e907b23
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/784d6f5c093ab5360670173ce001e1a446f95822 b/test/core/end2end/fuzzers/api_fuzzer_corpus/784d6f5c093ab5360670173ce001e1a446f95822
new file mode 100644
index 0000000..79885b7
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/784d6f5c093ab5360670173ce001e1a446f95822
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/79328fdc89d0af0e38da089dab062fd3ea5aae59 b/test/core/end2end/fuzzers/api_fuzzer_corpus/79328fdc89d0af0e38da089dab062fd3ea5aae59
new file mode 100644
index 0000000..4a5cbfd
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/79328fdc89d0af0e38da089dab062fd3ea5aae59
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/7a2569f4daf4480ad142cb4ee7c675bed82db74c b/test/core/end2end/fuzzers/api_fuzzer_corpus/7a2569f4daf4480ad142cb4ee7c675bed82db74c
new file mode 100644
index 0000000..75b55e7
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/7a2569f4daf4480ad142cb4ee7c675bed82db74c
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/87a300cd25d2e57745bd00499d4d2352a10a2fa1 b/test/core/end2end/fuzzers/api_fuzzer_corpus/87a300cd25d2e57745bd00499d4d2352a10a2fa1
new file mode 100644
index 0000000..c8f7986
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/87a300cd25d2e57745bd00499d4d2352a10a2fa1
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/8a1c629910280f8beebb88687696de98da988ecc b/test/core/end2end/fuzzers/api_fuzzer_corpus/8a1c629910280f8beebb88687696de98da988ecc
new file mode 100644
index 0000000..ce3377f
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/8a1c629910280f8beebb88687696de98da988ecc
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/8ff7b1568d2da2e4196c2e28617e1911d62021e6 b/test/core/end2end/fuzzers/api_fuzzer_corpus/8ff7b1568d2da2e4196c2e28617e1911d62021e6
new file mode 100644
index 0000000..321520b
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/8ff7b1568d2da2e4196c2e28617e1911d62021e6
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/982f375b183d984958667461c7767206062eb4cb b/test/core/end2end/fuzzers/api_fuzzer_corpus/982f375b183d984958667461c7767206062eb4cb
new file mode 100644
index 0000000..01d07d6
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/982f375b183d984958667461c7767206062eb4cb
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/98739af631223fa05ad88f1e63a52052a9bb4b1c b/test/core/end2end/fuzzers/api_fuzzer_corpus/98739af631223fa05ad88f1e63a52052a9bb4b1c
new file mode 100644
index 0000000..a4adb7a
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/98739af631223fa05ad88f1e63a52052a9bb4b1c
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/a78bca1ef8829d720dd5dedac3a9d4d12684da34 b/test/core/end2end/fuzzers/api_fuzzer_corpus/a78bca1ef8829d720dd5dedac3a9d4d12684da34
new file mode 100644
index 0000000..322d4ae
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/a78bca1ef8829d720dd5dedac3a9d4d12684da34
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/ac763d89466ebfad676e75be0076831c03fe2a5d b/test/core/end2end/fuzzers/api_fuzzer_corpus/ac763d89466ebfad676e75be0076831c03fe2a5d
new file mode 100644
index 0000000..64c9720
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/ac763d89466ebfad676e75be0076831c03fe2a5d
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/b165523f699e6ae9b2ad15873b9d56465d1af546 b/test/core/end2end/fuzzers/api_fuzzer_corpus/b165523f699e6ae9b2ad15873b9d56465d1af546
new file mode 100644
index 0000000..b0b7452
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/b165523f699e6ae9b2ad15873b9d56465d1af546
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/b2a5ec3ef40c68d594638218e3c943a479f82215 b/test/core/end2end/fuzzers/api_fuzzer_corpus/b2a5ec3ef40c68d594638218e3c943a479f82215
new file mode 100644
index 0000000..ac2b154
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/b2a5ec3ef40c68d594638218e3c943a479f82215
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/b92b1c5e0dba009a9516e7185f5df019c62c5cc9 b/test/core/end2end/fuzzers/api_fuzzer_corpus/b92b1c5e0dba009a9516e7185f5df019c62c5cc9
new file mode 100644
index 0000000..3d542f3
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/b92b1c5e0dba009a9516e7185f5df019c62c5cc9
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/c5cd7af16e7bc0049445d5a0b92a3d4b7e5e3533 b/test/core/end2end/fuzzers/api_fuzzer_corpus/c5cd7af16e7bc0049445d5a0b92a3d4b7e5e3533
new file mode 100644
index 0000000..c8fca17
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/c5cd7af16e7bc0049445d5a0b92a3d4b7e5e3533
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709 b/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/e28ffd8c2816f12f6395805199c792d1718191df b/test/core/end2end/fuzzers/api_fuzzer_corpus/e28ffd8c2816f12f6395805199c792d1718191df
new file mode 100644
index 0000000..a867a8b
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/e28ffd8c2816f12f6395805199c792d1718191df
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/ec823f4018389e64a99f6580277fba28df6bd136 b/test/core/end2end/fuzzers/api_fuzzer_corpus/ec823f4018389e64a99f6580277fba28df6bd136
new file mode 100644
index 0000000..2e6d409
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/ec823f4018389e64a99f6580277fba28df6bd136
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/ee2c1ac1e668f22836cf25a59495e778b0e2c7a8 b/test/core/end2end/fuzzers/api_fuzzer_corpus/ee2c1ac1e668f22836cf25a59495e778b0e2c7a8
new file mode 100644
index 0000000..f1990ac
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/ee2c1ac1e668f22836cf25a59495e778b0e2c7a8
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/ee6855178435d2046d8763ecae46e1e0a71a95f4 b/test/core/end2end/fuzzers/api_fuzzer_corpus/ee6855178435d2046d8763ecae46e1e0a71a95f4
new file mode 100644
index 0000000..6badaf3
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/ee6855178435d2046d8763ecae46e1e0a71a95f4
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/eeb310d91038cb02862e187e68c5d6578233485b b/test/core/end2end/fuzzers/api_fuzzer_corpus/eeb310d91038cb02862e187e68c5d6578233485b
new file mode 100644
index 0000000..1b05cfb
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/eeb310d91038cb02862e187e68c5d6578233485b
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/f07bc2907c95f2aeb79ca60e2ad826e13b848f45 b/test/core/end2end/fuzzers/api_fuzzer_corpus/f07bc2907c95f2aeb79ca60e2ad826e13b848f45
new file mode 100644
index 0000000..313d456
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/f07bc2907c95f2aeb79ca60e2ad826e13b848f45
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/fb655905396b768cf3ff015afdb0b564dae2cdfd b/test/core/end2end/fuzzers/api_fuzzer_corpus/fb655905396b768cf3ff015afdb0b564dae2cdfd
new file mode 100644
index 0000000..b02dabe
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/fb655905396b768cf3ff015afdb0b564dae2cdfd
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/fdb038087233cd176746558875932029f779221d b/test/core/end2end/fuzzers/api_fuzzer_corpus/fdb038087233cd176746558875932029f779221d
new file mode 100644
index 0000000..017fdbf
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/fdb038087233cd176746558875932029f779221d
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer.c b/test/core/end2end/fuzzers/client_fuzzer.c
index c5260cd..26b5208 100644
--- a/test/core/end2end/fuzzers/client_fuzzer.c
+++ b/test/core/end2end/fuzzers/client_fuzzer.c
@@ -62,7 +62,7 @@
       grpc_resource_quota_create("client_fuzzer");
   grpc_endpoint *mock_endpoint =
       grpc_mock_endpoint_create(discard_write, resource_quota);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
 
   grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
   grpc_transport *transport =
diff --git a/test/core/end2end/fuzzers/server_fuzzer.c b/test/core/end2end/fuzzers/server_fuzzer.c
index 164022e..115fb06 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.c
+++ b/test/core/end2end/fuzzers/server_fuzzer.c
@@ -60,7 +60,7 @@
       grpc_resource_quota_create("server_fuzzer");
   grpc_endpoint *mock_endpoint =
       grpc_mock_endpoint_create(discard_write, resource_quota);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_mock_endpoint_put_read(
       &exec_ctx, mock_endpoint,
       grpc_slice_from_copied_buffer((const char *)data, size));
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
new file mode 100755
index 0000000..ed1ba3e
--- /dev/null
+++ b/test/core/end2end/generate_tests.bzl
@@ -0,0 +1,192 @@
+#!/usr/bin/env python2.7
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Generates the appropriate build.json data for all the end2end tests."""
+
+
+def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True,
+                    secure=True, tracing=False,
+                    platforms=['windows', 'linux', 'mac', 'posix']):
+  return struct(
+    fullstack=fullstack,
+    includes_proxy=includes_proxy,
+    dns_resolver=dns_resolver,
+    secure=secure,
+    tracing=tracing,
+    #platforms=platforms
+  )
+
+
+# maps fixture name to whether it requires the security library
+END2END_FIXTURES = {
+    'h2_compress': fixture_options(),
+    'h2_census': fixture_options(),
+    'h2_load_reporting': fixture_options(),
+    'h2_fakesec': fixture_options(),
+    'h2_fd': fixture_options(dns_resolver=False, fullstack=False,
+                             platforms=['linux', 'mac', 'posix']),
+    'h2_full': fixture_options(),
+    'h2_full+pipe': fixture_options(platforms=['linux']),
+    'h2_full+trace': fixture_options(tracing=True),
+    'h2_http_proxy': fixture_options(),
+    'h2_oauth2': fixture_options(),
+    'h2_proxy': fixture_options(includes_proxy=True),
+    'h2_sockpair_1byte': fixture_options(fullstack=False, dns_resolver=False),
+    'h2_sockpair': fixture_options(fullstack=False, dns_resolver=False),
+    'h2_sockpair+trace': fixture_options(fullstack=False, dns_resolver=False,
+                                         tracing=True),
+    'h2_ssl': fixture_options(secure=True),
+    'h2_ssl_cert': fixture_options(secure=True),
+    'h2_ssl_proxy': fixture_options(secure=True),
+    'h2_uds': fixture_options(dns_resolver=False,
+                              platforms=['linux', 'mac', 'posix']),
+}
+
+
+def test_options(needs_fullstack=False, needs_dns=False, proxyable=True,
+                 secure=False, traceable=False):
+  return struct(
+    needs_fullstack=needs_fullstack,
+    needs_dns=needs_dns,
+    proxyable=proxyable,
+    secure=secure,
+    traceable=traceable
+  )
+
+
+# maps test names to options
+END2END_TESTS = {
+    'bad_hostname': test_options(),
+    'binary_metadata': test_options(),
+    'resource_quota_server': test_options(proxyable=False),
+    'call_creds': test_options(secure=True),
+    'cancel_after_accept': test_options(),
+    'cancel_after_client_done': test_options(),
+    'cancel_after_invoke': test_options(),
+    'cancel_before_invoke': test_options(),
+    'cancel_in_a_vacuum': test_options(),
+    'cancel_with_status': test_options(),
+    'compressed_payload': test_options(),
+    'connectivity': test_options(needs_fullstack=True, proxyable=False),
+    'default_host': test_options(needs_fullstack=True, needs_dns=True),
+    'disappearing_server': test_options(needs_fullstack=True),
+    'empty_batch': test_options(),
+    'filter_causes_close': test_options(),
+    'filter_call_init_fails': test_options(),
+    'graceful_server_shutdown': test_options(),
+    'hpack_size': test_options(proxyable=False, traceable=False),
+    'high_initial_seqno': test_options(),
+    'idempotent_request': test_options(),
+    'invoke_large_request': test_options(),
+    'large_metadata': test_options(),
+    'max_concurrent_streams': test_options(proxyable=False),
+    'max_message_length': test_options(),
+    'negative_deadline': test_options(),
+    'network_status_change': test_options(),
+    'no_logging': test_options(traceable=False),
+    'no_op': test_options(),
+    'payload': test_options(),
+    'load_reporting_hook': test_options(),
+    'ping_pong_streaming': test_options(),
+    'ping': test_options(proxyable=False),
+    'registered_call': test_options(),
+    'request_with_flags': test_options(proxyable=False),
+    'request_with_payload': test_options(),
+    'server_finishes_request': test_options(),
+    'shutdown_finishes_calls': test_options(),
+    'shutdown_finishes_tags': test_options(),
+    'simple_cacheable_request': test_options(),
+    'simple_delayed_request': test_options(needs_fullstack=True),
+    'simple_metadata': test_options(),
+    'simple_request': test_options(),
+    'streaming_error_response': test_options(),
+    'trailing_metadata': test_options(),
+    'authority_not_supported': test_options(),
+    'filter_latency': test_options(),
+}
+
+
+def compatible(fopt, topt):
+  if topt.needs_fullstack:
+    if not fopt.fullstack:
+      return False
+  if topt.needs_dns:
+    if not fopt.dns_resolver:
+      return False
+  if not topt.proxyable:
+    if fopt.includes_proxy:
+      return False
+  if not topt.traceable:
+    if fopt.tracing:
+      return False
+  return True
+
+
+def grpc_end2end_tests():
+  native.cc_library(
+    name = 'end2end_tests',
+    srcs = ['end2end_tests.c', 'end2end_test_utils.c'] + [
+             'tests/%s.c' % t
+             for t in sorted(END2END_TESTS.keys())],
+    hdrs = [
+      'tests/cancel_test_helpers.h',
+      'end2end_tests.h'
+    ],
+    copts = ['-std=c99'],
+    deps = [
+      ':cq_verifier',
+      ':ssl_test_data',
+      ':fake_resolver',
+      ':http_proxy',
+      ':proxy',
+      '//test/core/util:grpc_test_util',
+      '//:grpc',
+      '//test/core/util:gpr_test_util',
+      '//:gpr',
+    ]
+  )
+
+  for f, fopt in END2END_FIXTURES.items():
+    native.cc_binary(
+      name = '%s_test' % f,
+      srcs = ['fixtures/%s.c' % f],
+      copts = ['-std=c99'],
+      deps = [':end2end_tests']
+    )
+    for t, topt in END2END_TESTS.items():
+      #print(compatible(fopt, topt), f, t, fopt, topt)
+      if not compatible(fopt, topt): continue
+      native.sh_test(
+        name = '%s_test@%s' % (f, t),
+        srcs = ['end2end_test.sh'],
+        args = ['$(location %s_test)' % f, t],
+        data = [':%s_test' % f],
+      )
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
index 765b6ad..d974d2c 100644
--- a/test/core/end2end/invalid_call_argument_test.c
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -573,6 +573,29 @@
   cleanup_test();
 }
 
+static void test_invalid_initial_metadata_reserved_key() {
+  gpr_log(GPR_INFO, "test_invalid_initial_metadata_reserved_key");
+
+  grpc_metadata metadata;
+  metadata.key = ":start_with_colon";
+  metadata.value = "value";
+  metadata.value_length = 6;
+
+  grpc_op *op;
+  prepare_test(1);
+  op = g_state.ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 1;
+  op->data.send_initial_metadata.metadata = &metadata;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  GPR_ASSERT(GRPC_CALL_ERROR_INVALID_METADATA ==
+             grpc_call_start_batch(g_state.call, g_state.ops,
+                                   (size_t)(op - g_state.ops), tag(1), NULL));
+  cleanup_test();
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   grpc_init();
@@ -595,6 +618,7 @@
   test_send_server_status_twice();
   test_recv_close_on_server_with_invalid_flags();
   test_recv_close_on_server_twice();
+  test_invalid_initial_metadata_reserved_key();
   grpc_shutdown();
 
   return 0;
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index e582c59..a8e310c 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -251,7 +251,11 @@
   grpc_call_destroy(c);
   grpc_call_destroy(s);
 
-  if (args != NULL) grpc_channel_args_destroy(args);
+  if (args != NULL) {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   cq_verifier_destroy(cqv);
   end_test(&f);
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index 81fc709..d7efe77 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -140,8 +140,12 @@
       NULL, requested_client_compression_algorithm);
   server_args =
       grpc_channel_args_set_compression_algorithm(NULL, GRPC_COMPRESS_NONE);
-  server_args = grpc_channel_args_compression_algorithm_set_state(
-      &server_args, algorithm_to_disable, false);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    server_args = grpc_channel_args_compression_algorithm_set_state(
+        &exec_ctx, &server_args, algorithm_to_disable, false);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   f = begin_test(config, test_name, client_args, server_args);
   cqv = cq_verifier_create(f.cq);
@@ -262,8 +266,12 @@
   grpc_byte_buffer_destroy(request_payload);
   grpc_byte_buffer_destroy(request_payload_recv);
 
-  grpc_channel_args_destroy(client_args);
-  grpc_channel_args_destroy(server_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, client_args);
+    grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   end_test(&f);
   config.tear_down_data(&f);
@@ -512,8 +520,12 @@
 
   cq_verifier_destroy(cqv);
 
-  grpc_channel_args_destroy(client_args);
-  grpc_channel_args_destroy(server_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, client_args);
+    grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   end_test(&f);
   config.tear_down_data(&f);
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index 41ae575..ac9d2dd 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -216,9 +216,11 @@
                               const grpc_call_final_info *final_info,
                               void *and_free_memory) {}
 
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {}
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
+  return GRPC_ERROR_NONE;
+}
 
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {}
@@ -241,7 +243,8 @@
  * Registration
  */
 
-static bool maybe_add_filter(grpc_channel_stack_builder *builder, void *arg) {
+static bool maybe_add_filter(grpc_exec_ctx *exec_ctx,
+                             grpc_channel_stack_builder *builder, void *arg) {
   if (g_enable_filter) {
     // Want to add the filter as close to the end as possible, to make
     // sure that all of the filters work well together.  However, we
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index bf9fd90..45f623c 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -213,13 +213,13 @@
     grpc_slice message =
         grpc_slice_from_copied_string("Failure that's not preventable.");
     grpc_transport_stream_op *op = grpc_make_transport_stream_op(NULL);
-    grpc_transport_stream_op_add_close(op, GRPC_STATUS_PERMISSION_DENIED,
-                                       &message);
+    grpc_transport_stream_op_add_close(exec_ctx, op,
+                                       GRPC_STATUS_PERMISSION_DENIED, &message);
     grpc_call_next_op(exec_ctx, elem, op);
   }
-  grpc_exec_ctx_sched(
+  grpc_closure_sched(
       exec_ctx, calld->recv_im_ready,
-      GRPC_ERROR_CREATE_REFERENCING("Forced call to close", &error, 1), NULL);
+      GRPC_ERROR_CREATE_REFERENCING("Forced call to close", &error, 1));
 }
 
 static void start_transport_stream_op(grpc_exec_ctx *exec_ctx,
@@ -228,7 +228,8 @@
   call_data *calld = elem->call_data;
   if (op->recv_initial_metadata != NULL) {
     calld->recv_im_ready = op->recv_initial_metadata_ready;
-    op->recv_initial_metadata_ready = grpc_closure_create(recv_im_ready, elem);
+    op->recv_initial_metadata_ready =
+        grpc_closure_create(recv_im_ready, elem, grpc_schedule_on_exec_ctx);
   }
   grpc_call_next_op(exec_ctx, elem, op);
 }
@@ -243,9 +244,11 @@
                               const grpc_call_final_info *final_info,
                               void *and_free_memory) {}
 
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {}
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
+  return GRPC_ERROR_NONE;
+}
 
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {}
@@ -268,7 +271,8 @@
  * Registration
  */
 
-static bool maybe_add_filter(grpc_channel_stack_builder *builder, void *arg) {
+static bool maybe_add_filter(grpc_exec_ctx *exec_ctx,
+                             grpc_channel_stack_builder *builder, void *arg) {
   if (g_enable_filter) {
     return grpc_channel_stack_builder_prepend_filter(builder, &test_filter,
                                                      NULL, NULL);
diff --git a/test/core/end2end/tests/filter_latency.c b/test/core/end2end/tests/filter_latency.c
index ea63d45..dbb5c8d 100644
--- a/test/core/end2end/tests/filter_latency.c
+++ b/test/core/end2end/tests/filter_latency.c
@@ -281,9 +281,11 @@
   gpr_mu_unlock(&g_mu);
 }
 
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {}
+static grpc_error *init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_channel_element *elem,
+                                     grpc_channel_element_args *args) {
+  return GRPC_ERROR_NONE;
+}
 
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {}
@@ -320,7 +322,8 @@
  * Registration
  */
 
-static bool maybe_add_filter(grpc_channel_stack_builder *builder, void *arg) {
+static bool maybe_add_filter(grpc_exec_ctx *exec_ctx,
+                             grpc_channel_stack_builder *builder, void *arg) {
   grpc_channel_filter *filter = arg;
   if (g_enable_filter) {
     // Want to add the filter as close to the end as possible, to make
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index 5b75f26..ae5c270 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -311,7 +311,11 @@
                                 response_msg, &initial_lr_metadata,
                                 &trailing_lr_metadata);
   end_test(&f);
-  grpc_channel_args_destroy(lr_server_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, lr_server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   config.tear_down_data(&f);
 }
 
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index c222d9d..4a6ef44 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -168,8 +168,12 @@
 
   f = begin_test(config, "test_max_request_message_length", client_args,
                  server_args);
-  if (client_args != NULL) grpc_channel_args_destroy(client_args);
-  if (server_args != NULL) grpc_channel_args_destroy(server_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    if (client_args != NULL) grpc_channel_args_destroy(&exec_ctx, client_args);
+    if (server_args != NULL) grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   cqv = cq_verifier_create(f.cq);
 
@@ -342,9 +346,12 @@
 
   f = begin_test(config, "test_max_response_message_length", client_args,
                  server_args);
-  if (client_args != NULL) grpc_channel_args_destroy(client_args);
-  if (server_args != NULL) grpc_channel_args_destroy(server_args);
-
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    if (client_args != NULL) grpc_channel_args_destroy(&exec_ctx, client_args);
+    if (server_args != NULL) grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   cqv = cq_verifier_create(f.cq);
 
   c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/core/http/BUILD
old mode 100755
new mode 100644
similarity index 76%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/core/http/BUILD
index 7438713..58d265b
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/core/http/BUILD
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,21 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cd $(dirname $0)/../..
+grpc_fuzzer(
+  name = "response_fuzzer",
+  srcs = ["response_fuzzer.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "response_corpus",
+  copts = ["-std=c99"],
+)
 
-make grpc_csharp_ext
+grpc_fuzzer(
+  name = "request_fuzzer",
+  srcs = ["request_fuzzer.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "request_corpus",
+  copts = ["-std=c99"],
+)
 
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
diff --git a/test/core/http/httpcli_test.c b/test/core/http/httpcli_test.c
index 3e312c1..4cdbb5d 100644
--- a/test/core/http/httpcli_test.c
+++ b/test/core/http/httpcli_test.c
@@ -90,10 +90,11 @@
   grpc_http_response response;
   memset(&response, 0, sizeof(response));
   grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_get");
-  grpc_httpcli_get(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
-                   n_seconds_time(15),
-                   grpc_closure_create(on_finish, &response), &response);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_httpcli_get(
+      &exec_ctx, &g_context, &g_pops, resource_quota, &req, n_seconds_time(15),
+      grpc_closure_create(on_finish, &response, grpc_schedule_on_exec_ctx),
+      &response);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   gpr_mu_lock(g_mu);
   while (!g_done) {
     grpc_pollset_worker *worker = NULL;
@@ -130,10 +131,12 @@
   grpc_http_response response;
   memset(&response, 0, sizeof(response));
   grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_post");
-  grpc_httpcli_post(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
-                    "hello", 5, n_seconds_time(15),
-                    grpc_closure_create(on_finish, &response), &response);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_httpcli_post(
+      &exec_ctx, &g_context, &g_pops, resource_quota, &req, "hello", 5,
+      n_seconds_time(15),
+      grpc_closure_create(on_finish, &response, grpc_schedule_on_exec_ctx),
+      &response);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   gpr_mu_lock(g_mu);
   while (!g_done) {
     grpc_pollset_worker *worker = NULL;
@@ -207,7 +210,8 @@
   test_post(port);
 
   grpc_httpcli_context_destroy(&g_context);
-  grpc_closure_init(&destroyed, destroy_pops, &g_pops);
+  grpc_closure_init(&destroyed, destroy_pops, &g_pops,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
                         &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/http/httpscli_test.c b/test/core/http/httpscli_test.c
index d060351..72017cf 100644
--- a/test/core/http/httpscli_test.c
+++ b/test/core/http/httpscli_test.c
@@ -91,10 +91,11 @@
   grpc_http_response response;
   memset(&response, 0, sizeof(response));
   grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_get");
-  grpc_httpcli_get(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
-                   n_seconds_time(15),
-                   grpc_closure_create(on_finish, &response), &response);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_httpcli_get(
+      &exec_ctx, &g_context, &g_pops, resource_quota, &req, n_seconds_time(15),
+      grpc_closure_create(on_finish, &response, grpc_schedule_on_exec_ctx),
+      &response);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   gpr_mu_lock(g_mu);
   while (!g_done) {
     grpc_pollset_worker *worker = NULL;
@@ -132,10 +133,12 @@
   grpc_http_response response;
   memset(&response, 0, sizeof(response));
   grpc_resource_quota *resource_quota = grpc_resource_quota_create("test_post");
-  grpc_httpcli_post(&exec_ctx, &g_context, &g_pops, resource_quota, &req,
-                    "hello", 5, n_seconds_time(15),
-                    grpc_closure_create(on_finish, &response), &response);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_httpcli_post(
+      &exec_ctx, &g_context, &g_pops, resource_quota, &req, "hello", 5,
+      n_seconds_time(15),
+      grpc_closure_create(on_finish, &response, grpc_schedule_on_exec_ctx),
+      &response);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   gpr_mu_lock(g_mu);
   while (!g_done) {
     grpc_pollset_worker *worker = NULL;
@@ -210,7 +213,8 @@
   test_post(port);
 
   grpc_httpcli_context_destroy(&g_context);
-  grpc_closure_init(&destroyed, destroy_pops, &g_pops);
+  grpc_closure_init(&destroyed, destroy_pops, &g_pops,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, grpc_polling_entity_pollset(&g_pops),
                         &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/internal_api_canaries/iomgr.c b/test/core/internal_api_canaries/iomgr.c
index de03c47..3225b9d 100644
--- a/test/core/internal_api_canaries/iomgr.c
+++ b/test/core/internal_api_canaries/iomgr.c
@@ -48,7 +48,7 @@
 static void test_code(void) {
   /* iomgr.h */
   grpc_iomgr_init();
-  grpc_iomgr_shutdown();
+  grpc_iomgr_shutdown(NULL);
 
   /* closure.h */
   grpc_closure closure;
@@ -60,9 +60,9 @@
   closure_list.head = NULL;
   closure_list.tail = NULL;
 
-  grpc_closure_init(&closure, NULL, NULL);
+  grpc_closure_init(&closure, NULL, NULL, grpc_schedule_on_exec_ctx);
 
-  grpc_closure_create(NULL, NULL);
+  grpc_closure_create(NULL, NULL, grpc_schedule_on_exec_ctx);
 
   grpc_closure_list_move(NULL, NULL);
   grpc_closure_list_append(NULL, NULL, GRPC_ERROR_CREATE("Foo"));
@@ -72,8 +72,8 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_exec_ctx_flush(&exec_ctx);
   grpc_exec_ctx_finish(&exec_ctx);
-  grpc_exec_ctx_sched(&exec_ctx, &closure, GRPC_ERROR_CREATE("Foo"), NULL);
-  grpc_exec_ctx_enqueue_list(&exec_ctx, &closure_list, NULL);
+  grpc_closure_sched(&exec_ctx, &closure, GRPC_ERROR_CREATE("Foo"));
+  grpc_closure_list_sched(&exec_ctx, &closure_list);
 
   /* endpoint.h */
   grpc_endpoint endpoint;
@@ -99,8 +99,7 @@
 
   /* executor.h */
   grpc_executor_init();
-  grpc_executor_push(&closure, GRPC_ERROR_CREATE("Phi"));
-  grpc_executor_shutdown();
+  grpc_executor_shutdown(NULL);
 
   /* pollset.h */
   grpc_pollset_size();
diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c
index f7d5809..9b6d6ff 100644
--- a/test/core/iomgr/combiner_test.c
+++ b/test/core/iomgr/combiner_test.c
@@ -59,9 +59,10 @@
   grpc_combiner *lock = grpc_combiner_create(NULL);
   bool done = false;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_combiner_execute(&exec_ctx, lock,
-                        grpc_closure_create(set_bool_to_true, &done),
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(&exec_ctx,
+                     grpc_closure_create(set_bool_to_true, &done,
+                                         grpc_combiner_scheduler(lock, false)),
+                     GRPC_ERROR_NONE);
   grpc_exec_ctx_flush(&exec_ctx);
   GPR_ASSERT(done);
   grpc_combiner_destroy(&exec_ctx, lock);
@@ -94,9 +95,10 @@
       ex_args *c = gpr_malloc(sizeof(*c));
       c->ctr = &args->ctr;
       c->value = n++;
-      grpc_combiner_execute(&exec_ctx, args->lock,
-                            grpc_closure_create(check_one, c), GRPC_ERROR_NONE,
-                            false);
+      grpc_closure_sched(
+          &exec_ctx, grpc_closure_create(check_one, c, grpc_combiner_scheduler(
+                                                           args->lock, false)),
+          GRPC_ERROR_NONE);
       grpc_exec_ctx_flush(&exec_ctx);
     }
     // sleep for a little bit, to test a combiner draining and another thread
@@ -134,9 +136,10 @@
 }
 
 static void add_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
-  grpc_combiner_execute_finally(exec_ctx, arg,
-                                grpc_closure_create(in_finally, NULL),
-                                GRPC_ERROR_NONE, false);
+  grpc_closure_sched(exec_ctx, grpc_closure_create(
+                                   in_finally, NULL,
+                                   grpc_combiner_finally_scheduler(arg, false)),
+                     GRPC_ERROR_NONE);
 }
 
 static void test_execute_finally(void) {
@@ -144,8 +147,10 @@
 
   grpc_combiner *lock = grpc_combiner_create(NULL);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(add_finally, lock),
-                        GRPC_ERROR_NONE, false);
+  grpc_closure_sched(&exec_ctx,
+                     grpc_closure_create(add_finally, lock,
+                                         grpc_combiner_scheduler(lock, false)),
+                     GRPC_ERROR_NONE);
   grpc_exec_ctx_flush(&exec_ctx);
   GPR_ASSERT(got_in_finally);
   grpc_combiner_destroy(&exec_ctx, lock);
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index 2a257a7..f02171f 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -81,7 +81,8 @@
   g_pollset = gpr_malloc(grpc_pollset_size());
   grpc_pollset_init(g_pollset, &g_mu);
   grpc_endpoint_tests(configs[0], g_pollset, g_mu);
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index 8186ea7..df5dd20 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -41,6 +41,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
 /*
@@ -211,9 +213,10 @@
   state.write_done = 0;
   state.current_read_data = 0;
   state.current_write_data = 0;
-  grpc_closure_init(&state.done_read, read_and_write_test_read_handler, &state);
+  grpc_closure_init(&state.done_read, read_and_write_test_read_handler, &state,
+                    grpc_schedule_on_exec_ctx);
   grpc_closure_init(&state.done_write, read_and_write_test_write_handler,
-                    &state);
+                    &state, grpc_schedule_on_exec_ctx);
   grpc_slice_buffer_init(&state.outgoing);
   grpc_slice_buffer_init(&state.incoming);
 
@@ -249,8 +252,8 @@
   grpc_exec_ctx_flush(&exec_ctx);
 
   end_test(config);
-  grpc_slice_buffer_destroy(&state.outgoing);
-  grpc_slice_buffer_destroy(&state.incoming);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &state.outgoing);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &state.incoming);
   grpc_endpoint_destroy(&exec_ctx, state.read_ep);
   grpc_endpoint_destroy(&exec_ctx, state.write_ep);
   grpc_exec_ctx_finish(&exec_ctx);
@@ -290,21 +293,24 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_endpoint_add_to_pollset(&exec_ctx, f.client_ep, g_pollset);
   grpc_endpoint_read(&exec_ctx, f.client_ep, &slice_buffer,
-                     grpc_closure_create(inc_on_failure, &fail_count));
+                     grpc_closure_create(inc_on_failure, &fail_count,
+                                         grpc_schedule_on_exec_ctx));
   wait_for_fail_count(&exec_ctx, &fail_count, 0);
   grpc_endpoint_shutdown(&exec_ctx, f.client_ep);
   wait_for_fail_count(&exec_ctx, &fail_count, 1);
   grpc_endpoint_read(&exec_ctx, f.client_ep, &slice_buffer,
-                     grpc_closure_create(inc_on_failure, &fail_count));
+                     grpc_closure_create(inc_on_failure, &fail_count,
+                                         grpc_schedule_on_exec_ctx));
   wait_for_fail_count(&exec_ctx, &fail_count, 2);
   grpc_slice_buffer_add(&slice_buffer, grpc_slice_from_copied_string("a"));
   grpc_endpoint_write(&exec_ctx, f.client_ep, &slice_buffer,
-                      grpc_closure_create(inc_on_failure, &fail_count));
+                      grpc_closure_create(inc_on_failure, &fail_count,
+                                          grpc_schedule_on_exec_ctx));
   wait_for_fail_count(&exec_ctx, &fail_count, 3);
   grpc_endpoint_shutdown(&exec_ctx, f.client_ep);
   wait_for_fail_count(&exec_ctx, &fail_count, 3);
 
-  grpc_slice_buffer_destroy(&slice_buffer);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &slice_buffer);
 
   grpc_endpoint_destroy(&exec_ctx, f.client_ep);
   grpc_endpoint_destroy(&exec_ctx, f.server_ep);
diff --git a/test/core/iomgr/ev_epoll_linux_test.c b/test/core/iomgr/ev_epoll_linux_test.c
index 564b05d..40ae91b 100644
--- a/test/core/iomgr/ev_epoll_linux_test.c
+++ b/test/core/iomgr/ev_epoll_linux_test.c
@@ -102,7 +102,8 @@
   int i;
 
   for (i = 0; i < num_pollsets; i++) {
-    grpc_closure_init(&destroyed, destroy_pollset, pollsets[i].pollset);
+    grpc_closure_init(&destroyed, destroy_pollset, pollsets[i].pollset,
+                      grpc_schedule_on_exec_ctx);
     grpc_pollset_shutdown(exec_ctx, pollsets[i].pollset, &destroyed);
 
     grpc_exec_ctx_flush(exec_ctx);
@@ -236,7 +237,11 @@
             "strategy. and the current strategy is: '%s'",
             poll_strategy);
   }
-  grpc_iomgr_shutdown();
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_iomgr_shutdown(&exec_ctx);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   return 0;
 }
 #else /* defined(GRPC_LINUX_EPOLL) */
diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c
index 652b37e..3dffa02 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -65,6 +65,10 @@
 
   grpc_resource_quota_unref(resource_quota);
 
-  grpc_iomgr_shutdown();
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_iomgr_shutdown(&exec_ctx);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   return 0;
 }
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index 6166699..a617bfc 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -219,8 +219,8 @@
   se->sv = sv;
   se->em_fd = grpc_fd_create(fd, "listener");
   grpc_pollset_add_fd(exec_ctx, g_pollset, se->em_fd);
-  se->session_read_closure.cb = session_read_cb;
-  se->session_read_closure.cb_arg = se;
+  grpc_closure_init(&se->session_read_closure, session_read_cb, se,
+                    grpc_schedule_on_exec_ctx);
   grpc_fd_notify_on_read(exec_ctx, se->em_fd, &se->session_read_closure);
 
   grpc_fd_notify_on_read(exec_ctx, listen_em_fd, &sv->listen_closure);
@@ -249,8 +249,8 @@
   sv->em_fd = grpc_fd_create(fd, "server");
   grpc_pollset_add_fd(exec_ctx, g_pollset, sv->em_fd);
   /* Register to be interested in reading from listen_fd. */
-  sv->listen_closure.cb = listen_cb;
-  sv->listen_closure.cb_arg = sv;
+  grpc_closure_init(&sv->listen_closure, listen_cb, sv,
+                    grpc_schedule_on_exec_ctx);
   grpc_fd_notify_on_read(exec_ctx, sv->em_fd, &sv->listen_closure);
 
   return port;
@@ -333,8 +333,8 @@
   if (errno == EAGAIN) {
     gpr_mu_lock(g_mu);
     if (cl->client_write_cnt < CLIENT_TOTAL_WRITE_CNT) {
-      cl->write_closure.cb = client_session_write;
-      cl->write_closure.cb_arg = cl;
+      grpc_closure_init(&cl->write_closure, client_session_write, cl,
+                        grpc_schedule_on_exec_ctx);
       grpc_fd_notify_on_write(exec_ctx, cl->em_fd, &cl->write_closure);
       cl->client_write_cnt++;
     } else {
@@ -459,10 +459,10 @@
   grpc_closure second_closure;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
-  first_closure.cb = first_read_callback;
-  first_closure.cb_arg = &a;
-  second_closure.cb = second_read_callback;
-  second_closure.cb_arg = &b;
+  grpc_closure_init(&first_closure, first_read_callback, &a,
+                    grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&second_closure, second_read_callback, &b,
+                    grpc_schedule_on_exec_ctx);
 
   init_change_data(&a);
   init_change_data(&b);
@@ -546,11 +546,13 @@
   grpc_pollset_init(g_pollset, &g_mu);
   test_grpc_fd();
   test_grpc_fd_change();
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
-  grpc_exec_ctx_finish(&exec_ctx);
+  grpc_exec_ctx_flush(&exec_ctx);
   gpr_free(g_pollset);
-  grpc_iomgr_shutdown();
+  grpc_iomgr_shutdown(&exec_ctx);
+  grpc_exec_ctx_finish(&exec_ctx);
   return 0;
 }
 
diff --git a/test/core/iomgr/resolve_address_test.c b/test/core/iomgr/resolve_address_test.c
index 2dd0d88..84f4ed4 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -32,8 +32,10 @@
  */
 
 #include "src/core/lib/iomgr/resolve_address.h"
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
@@ -46,16 +48,73 @@
 typedef struct args_struct {
   gpr_event ev;
   grpc_resolved_addresses *addrs;
+  gpr_atm done_atm;
+  gpr_mu *mu;
+  grpc_pollset *pollset;
+  grpc_pollset_set *pollset_set;
 } args_struct;
 
-void args_init(args_struct *args) {
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
+
+void args_init(grpc_exec_ctx *exec_ctx, args_struct *args) {
   gpr_event_init(&args->ev);
+  args->pollset = gpr_malloc(grpc_pollset_size());
+  grpc_pollset_init(args->pollset, &args->mu);
+  args->pollset_set = grpc_pollset_set_create();
+  grpc_pollset_set_add_pollset(exec_ctx, args->pollset_set, args->pollset);
   args->addrs = NULL;
 }
 
-void args_finish(args_struct *args) {
+void args_finish(grpc_exec_ctx *exec_ctx, args_struct *args) {
   GPR_ASSERT(gpr_event_wait(&args->ev, test_deadline()));
   grpc_resolved_addresses_destroy(args->addrs);
+  grpc_pollset_set_del_pollset(exec_ctx, args->pollset_set, args->pollset);
+  grpc_pollset_set_destroy(args->pollset_set);
+  grpc_closure do_nothing_cb;
+  grpc_closure_init(&do_nothing_cb, do_nothing, NULL,
+                    grpc_schedule_on_exec_ctx);
+  grpc_pollset_shutdown(exec_ctx, args->pollset, &do_nothing_cb);
+  // exec_ctx needs to be flushed before calling grpc_pollset_destroy()
+  grpc_exec_ctx_flush(exec_ctx);
+  grpc_pollset_destroy(args->pollset);
+  gpr_free(args->pollset);
+}
+
+static gpr_timespec n_sec_deadline(int seconds) {
+  return gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                      gpr_time_from_seconds(seconds, GPR_TIMESPAN));
+}
+
+static void actually_poll(void *argsp) {
+  args_struct *args = argsp;
+  gpr_timespec deadline = n_sec_deadline(10);
+  while (true) {
+    bool done = gpr_atm_acq_load(&args->done_atm) != 0;
+    if (done) {
+      break;
+    }
+    gpr_timespec time_left =
+        gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME));
+    gpr_log(GPR_DEBUG, "done=%d, time_left=%" PRId64 ".%09d", done,
+            time_left.tv_sec, time_left.tv_nsec);
+    GPR_ASSERT(gpr_time_cmp(time_left, gpr_time_0(GPR_TIMESPAN)) >= 0);
+    grpc_pollset_worker *worker = NULL;
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    gpr_mu_lock(args->mu);
+    GRPC_LOG_IF_ERROR(
+        "pollset_work",
+        grpc_pollset_work(&exec_ctx, args->pollset, &worker,
+                          gpr_now(GPR_CLOCK_REALTIME), n_sec_deadline(1)));
+    gpr_mu_unlock(args->mu);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+  gpr_event_set(&args->ev, (void *)1);
+}
+
+static void poll_pollset_until_request_done(args_struct *args) {
+  gpr_atm_rel_store(&args->done_atm, 0);
+  gpr_thd_id id;
+  gpr_thd_new(&id, actually_poll, args, NULL);
 }
 
 static void must_succeed(grpc_exec_ctx *exec_ctx, void *argsp,
@@ -64,53 +123,65 @@
   GPR_ASSERT(err == GRPC_ERROR_NONE);
   GPR_ASSERT(args->addrs != NULL);
   GPR_ASSERT(args->addrs->naddrs > 0);
-  gpr_event_set(&args->ev, (void *)1);
+  gpr_atm_rel_store(&args->done_atm, 1);
 }
 
 static void must_fail(grpc_exec_ctx *exec_ctx, void *argsp, grpc_error *err) {
   args_struct *args = argsp;
   GPR_ASSERT(err != GRPC_ERROR_NONE);
-  gpr_event_set(&args->ev, (void *)1);
+  gpr_atm_rel_store(&args->done_atm, 1);
 }
 
 static void test_localhost(void) {
-  args_struct args;
-  args_init(&args);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_resolve_address(&exec_ctx, "localhost:1", NULL,
-                       grpc_closure_create(must_succeed, &args), &args.addrs);
+  args_struct args;
+  args_init(&exec_ctx, &args);
+  poll_pollset_until_request_done(&args);
+  grpc_resolve_address(
+      &exec_ctx, "localhost:1", NULL, args.pollset_set,
+      grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
+      &args.addrs);
+  args_finish(&exec_ctx, &args);
   grpc_exec_ctx_finish(&exec_ctx);
-  args_finish(&args);
 }
 
 static void test_default_port(void) {
-  args_struct args;
-  args_init(&args);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_resolve_address(&exec_ctx, "localhost", "1",
-                       grpc_closure_create(must_succeed, &args), &args.addrs);
+  args_struct args;
+  args_init(&exec_ctx, &args);
+  poll_pollset_until_request_done(&args);
+  grpc_resolve_address(
+      &exec_ctx, "localhost", "1", args.pollset_set,
+      grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
+      &args.addrs);
+  args_finish(&exec_ctx, &args);
   grpc_exec_ctx_finish(&exec_ctx);
-  args_finish(&args);
 }
 
 static void test_missing_default_port(void) {
-  args_struct args;
-  args_init(&args);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_resolve_address(&exec_ctx, "localhost", NULL,
-                       grpc_closure_create(must_fail, &args), &args.addrs);
+  args_struct args;
+  args_init(&exec_ctx, &args);
+  poll_pollset_until_request_done(&args);
+  grpc_resolve_address(
+      &exec_ctx, "localhost", NULL, args.pollset_set,
+      grpc_closure_create(must_fail, &args, grpc_schedule_on_exec_ctx),
+      &args.addrs);
+  args_finish(&exec_ctx, &args);
   grpc_exec_ctx_finish(&exec_ctx);
-  args_finish(&args);
 }
 
 static void test_ipv6_with_port(void) {
-  args_struct args;
-  args_init(&args);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_resolve_address(&exec_ctx, "[2001:db8::1]:1", NULL,
-                       grpc_closure_create(must_succeed, &args), &args.addrs);
+  args_struct args;
+  args_init(&exec_ctx, &args);
+  poll_pollset_until_request_done(&args);
+  grpc_resolve_address(
+      &exec_ctx, "[2001:db8::1]:1", NULL, args.pollset_set,
+      grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
+      &args.addrs);
+  args_finish(&exec_ctx, &args);
   grpc_exec_ctx_finish(&exec_ctx);
-  args_finish(&args);
 }
 
 static void test_ipv6_without_port(void) {
@@ -119,13 +190,16 @@
   };
   unsigned i;
   for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) {
-    args_struct args;
-    args_init(&args);
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resolve_address(&exec_ctx, kCases[i], "80",
-                         grpc_closure_create(must_succeed, &args), &args.addrs);
+    args_struct args;
+    args_init(&exec_ctx, &args);
+    poll_pollset_until_request_done(&args);
+    grpc_resolve_address(
+        &exec_ctx, kCases[i], "80", args.pollset_set,
+        grpc_closure_create(must_succeed, &args, grpc_schedule_on_exec_ctx),
+        &args.addrs);
+    args_finish(&exec_ctx, &args);
     grpc_exec_ctx_finish(&exec_ctx);
-    args_finish(&args);
   }
 }
 
@@ -135,13 +209,16 @@
   };
   unsigned i;
   for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) {
-    args_struct args;
-    args_init(&args);
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resolve_address(&exec_ctx, kCases[i], NULL,
-                         grpc_closure_create(must_fail, &args), &args.addrs);
+    args_struct args;
+    args_init(&exec_ctx, &args);
+    poll_pollset_until_request_done(&args);
+    grpc_resolve_address(
+        &exec_ctx, kCases[i], NULL, args.pollset_set,
+        grpc_closure_create(must_fail, &args, grpc_schedule_on_exec_ctx),
+        &args.addrs);
+    args_finish(&exec_ctx, &args);
     grpc_exec_ctx_finish(&exec_ctx);
-    args_finish(&args);
   }
 }
 
@@ -151,13 +228,16 @@
   };
   unsigned i;
   for (i = 0; i < sizeof(kCases) / sizeof(*kCases); i++) {
-    args_struct args;
-    args_init(&args);
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    grpc_resolve_address(&exec_ctx, kCases[i], "1",
-                         grpc_closure_create(must_fail, &args), &args.addrs);
+    args_struct args;
+    args_init(&exec_ctx, &args);
+    poll_pollset_until_request_done(&args);
+    grpc_resolve_address(
+        &exec_ctx, kCases[i], "1", args.pollset_set,
+        grpc_closure_create(must_fail, &args, grpc_schedule_on_exec_ctx),
+        &args.addrs);
+    args_finish(&exec_ctx, &args);
     grpc_exec_ctx_finish(&exec_ctx);
-    args_finish(&args);
   }
 }
 
@@ -172,7 +252,11 @@
   test_ipv6_without_port();
   test_invalid_ip_addresses();
   test_unparseable_hostports();
-  grpc_iomgr_shutdown();
-  grpc_executor_shutdown();
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_executor_shutdown(&exec_ctx);
+    grpc_iomgr_shutdown(&exec_ctx);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   return 0;
 }
diff --git a/test/core/iomgr/resource_quota_test.c b/test/core/iomgr/resource_quota_test.c
index a82d44f..a5b28f2 100644
--- a/test/core/iomgr/resource_quota_test.c
+++ b/test/core/iomgr/resource_quota_test.c
@@ -36,6 +36,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
 static void inc_int_cb(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) {
@@ -45,7 +46,9 @@
 static void set_bool_cb(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) {
   *(bool *)a = true;
 }
-grpc_closure *set_bool(bool *p) { return grpc_closure_create(set_bool_cb, p); }
+grpc_closure *set_bool(bool *p) {
+  return grpc_closure_create(set_bool_cb, p, grpc_schedule_on_exec_ctx);
+}
 
 typedef struct {
   size_t size;
@@ -67,7 +70,7 @@
   a->size = size;
   a->resource_user = resource_user;
   a->then = then;
-  return grpc_closure_create(reclaimer_cb, a);
+  return grpc_closure_create(reclaimer_cb, a, grpc_schedule_on_exec_ctx);
 }
 
 static void unused_reclaimer_cb(grpc_exec_ctx *exec_ctx, void *arg,
@@ -76,7 +79,8 @@
   grpc_closure_run(exec_ctx, arg, GRPC_ERROR_NONE);
 }
 grpc_closure *make_unused_reclaimer(grpc_closure *then) {
-  return grpc_closure_create(unused_reclaimer_cb, then);
+  return grpc_closure_create(unused_reclaimer_cb, then,
+                             grpc_schedule_on_exec_ctx);
 }
 
 static void destroy_user(grpc_resource_user *usr) {
@@ -631,7 +635,11 @@
     GPR_ASSERT(num_allocs == start_allocs + 1);
   }
 
-  grpc_slice_buffer_destroy(&buffer);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   destroy_user(usr);
   grpc_resource_quota_unref(q);
 }
@@ -667,7 +675,11 @@
   }
 
   grpc_resource_quota_unref(q);
-  grpc_slice_buffer_destroy(&buffer);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 5fab826..0ea7a00 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -113,7 +113,7 @@
   /* connect to it */
   GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)addr,
                          (socklen_t *)&resolved_addr.len) == 0);
-  grpc_closure_init(&done, must_succeed, NULL);
+  grpc_closure_init(&done, must_succeed, NULL, grpc_schedule_on_exec_ctx);
   grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set, NULL,
                           &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
 
@@ -163,7 +163,7 @@
   gpr_mu_unlock(g_mu);
 
   /* connect to a broken address */
-  grpc_closure_init(&done, must_fail, NULL);
+  grpc_closure_init(&done, must_fail, NULL, grpc_schedule_on_exec_ctx);
   grpc_tcp_client_connect(&exec_ctx, &done, &g_connecting, g_pollset_set, NULL,
                           &resolved_addr, gpr_inf_future(GPR_CLOCK_REALTIME));
 
@@ -207,7 +207,8 @@
   gpr_log(GPR_ERROR, "End of first test");
   test_fails();
   grpc_pollset_set_destroy(g_pollset_set);
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index 5eafa57..cabb64e 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -50,6 +50,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/iomgr/endpoint_tests.h"
 #include "test/core/util/test_config.h"
 
@@ -184,7 +186,7 @@
   grpc_resource_quota *resource_quota = grpc_resource_quota_create("read_test");
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
                        slice_size, "test");
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -194,7 +196,7 @@
   state.read_bytes = 0;
   state.target_read_bytes = written_bytes;
   grpc_slice_buffer_init(&state.incoming);
-  grpc_closure_init(&state.read_cb, read_cb, &state);
+  grpc_closure_init(&state.read_cb, read_cb, &state, grpc_schedule_on_exec_ctx);
 
   grpc_endpoint_read(&exec_ctx, ep, &state.incoming, &state.read_cb);
 
@@ -212,7 +214,7 @@
   GPR_ASSERT(state.read_bytes == state.target_read_bytes);
   gpr_mu_unlock(g_mu);
 
-  grpc_slice_buffer_destroy(&state.incoming);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &state.incoming);
   grpc_endpoint_destroy(&exec_ctx, ep);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -235,7 +237,7 @@
       grpc_resource_quota_create("large_read_test");
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), resource_quota,
                        slice_size, "test");
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket(sv[0]);
@@ -245,7 +247,7 @@
   state.read_bytes = 0;
   state.target_read_bytes = (size_t)written_bytes;
   grpc_slice_buffer_init(&state.incoming);
-  grpc_closure_init(&state.read_cb, read_cb, &state);
+  grpc_closure_init(&state.read_cb, read_cb, &state, grpc_schedule_on_exec_ctx);
 
   grpc_endpoint_read(&exec_ctx, ep, &state.incoming, &state.read_cb);
 
@@ -263,7 +265,7 @@
   GPR_ASSERT(state.read_bytes == state.target_read_bytes);
   gpr_mu_unlock(g_mu);
 
-  grpc_slice_buffer_destroy(&state.incoming);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &state.incoming);
   grpc_endpoint_destroy(&exec_ctx, ep);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -374,7 +376,7 @@
       grpc_resource_quota_create("write_test");
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), resource_quota,
                        GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   state.ep = ep;
@@ -384,7 +386,8 @@
 
   grpc_slice_buffer_init(&outgoing);
   grpc_slice_buffer_addn(&outgoing, slices, num_blocks);
-  grpc_closure_init(&write_done_closure, write_done, &state);
+  grpc_closure_init(&write_done_closure, write_done, &state,
+                    grpc_schedule_on_exec_ctx);
 
   grpc_endpoint_write(&exec_ctx, ep, &outgoing, &write_done_closure);
   drain_socket_blocking(sv[0], num_bytes, num_bytes);
@@ -404,7 +407,7 @@
   }
   gpr_mu_unlock(g_mu);
 
-  grpc_slice_buffer_destroy(&outgoing);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &outgoing);
   grpc_endpoint_destroy(&exec_ctx, ep);
   gpr_free(slices);
   grpc_exec_ctx_finish(&exec_ctx);
@@ -429,7 +432,8 @@
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_closure fd_released_cb;
   int fd_released_done = 0;
-  grpc_closure_init(&fd_released_cb, &on_fd_released, &fd_released_done);
+  grpc_closure_init(&fd_released_cb, &on_fd_released, &fd_released_done,
+                    grpc_schedule_on_exec_ctx);
 
   gpr_log(GPR_INFO,
           "Release fd read_test of size %" PRIuPTR ", slice size %" PRIuPTR,
@@ -442,7 +446,7 @@
   ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
                        slice_size, "test");
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -452,7 +456,7 @@
   state.read_bytes = 0;
   state.target_read_bytes = written_bytes;
   grpc_slice_buffer_init(&state.incoming);
-  grpc_closure_init(&state.read_cb, read_cb, &state);
+  grpc_closure_init(&state.read_cb, read_cb, &state, grpc_schedule_on_exec_ctx);
 
   grpc_endpoint_read(&exec_ctx, ep, &state.incoming, &state.read_cb);
 
@@ -472,7 +476,7 @@
   GPR_ASSERT(state.read_bytes == state.target_read_bytes);
   gpr_mu_unlock(g_mu);
 
-  grpc_slice_buffer_destroy(&state.incoming);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &state.incoming);
   grpc_tcp_destroy_and_release_fd(&exec_ctx, ep, &fd, &fd_released_cb);
   grpc_exec_ctx_flush(&exec_ctx);
   gpr_mu_lock(g_mu);
@@ -534,7 +538,7 @@
                                 resource_quota, slice_size, "test");
   f.server_ep = grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"),
                                 resource_quota, slice_size, "test");
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, f.client_ep, g_pollset);
   grpc_endpoint_add_to_pollset(&exec_ctx, f.server_ep, g_pollset);
 
@@ -561,7 +565,8 @@
   grpc_pollset_init(g_pollset, &g_mu);
   grpc_endpoint_tests(configs[0], g_pollset, g_mu);
   run_tests();
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 9a7810e..020f005 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -104,7 +104,7 @@
 static void server_weak_ref_init(server_weak_ref *weak_ref) {
   weak_ref->server = NULL;
   grpc_closure_init(&weak_ref->server_shutdown, server_weak_ref_shutdown,
-                    weak_ref);
+                    weak_ref, grpc_schedule_on_exec_ctx);
 }
 
 /* Make weak_ref->server_shutdown a shutdown_starting cb on server.
@@ -366,7 +366,8 @@
   test_connect(1);
   test_connect(10);
 
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index be8988a..8d7ac3f 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -57,17 +57,20 @@
 
   /* 10 ms timers.  will expire in the current epoch */
   for (i = 0; i < 10; i++) {
-    grpc_timer_init(&exec_ctx, &timers[i],
-                    gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
-                    cb, (void *)(intptr_t)i, start);
+    grpc_timer_init(
+        &exec_ctx, &timers[i],
+        gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
+        grpc_closure_create(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx),
+        start);
   }
 
   /* 1010 ms timers.  will expire in the next epoch */
   for (i = 10; i < 20; i++) {
     grpc_timer_init(
         &exec_ctx, &timers[i],
-        gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)), cb,
-        (void *)(intptr_t)i, start);
+        gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)),
+        grpc_closure_create(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx),
+        start);
   }
 
   /* collect timers.  Only the first batch should be ready. */
@@ -125,16 +128,26 @@
   grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
   memset(cb_called, 0, sizeof(cb_called));
 
-  grpc_timer_init(&exec_ctx, &timers[0], tfm(100), cb, (void *)(intptr_t)0,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[1], tfm(3), cb, (void *)(intptr_t)1,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[2], tfm(100), cb, (void *)(intptr_t)2,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[3], tfm(3), cb, (void *)(intptr_t)3,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[4], tfm(1), cb, (void *)(intptr_t)4,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[0], tfm(100),
+      grpc_closure_create(cb, (void *)(intptr_t)0, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[1], tfm(3),
+      grpc_closure_create(cb, (void *)(intptr_t)1, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[2], tfm(100),
+      grpc_closure_create(cb, (void *)(intptr_t)2, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[3], tfm(3),
+      grpc_closure_create(cb, (void *)(intptr_t)3, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[4], tfm(1),
+      grpc_closure_create(cb, (void *)(intptr_t)4, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
   GPR_ASSERT(1 == grpc_timer_check(&exec_ctx, tfm(2), NULL));
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_ASSERT(1 == cb_called[4][1]);
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index 9bea229..e121040 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -234,11 +234,12 @@
   test_receive(1);
   test_receive(10);
 
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
   gpr_free(g_pollset);
-  grpc_iomgr_shutdown();
+  grpc_shutdown();
   return 0;
 }
 
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/core/json/BUILD
old mode 100755
new mode 100644
similarity index 86%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/core/json/BUILD
index 7438713..4b3fbd6
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/core/json/BUILD
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,13 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cd $(dirname $0)/../..
+grpc_fuzzer(
+  name = "json_fuzzer",
+  srcs = ["fuzzer.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "corpus",
+  copts = ["-std=c99"],
+)
 
-make grpc_csharp_ext
-
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
diff --git a/test/core/memory_usage/client.c b/test/core/memory_usage/client.c
new file mode 100644
index 0000000..9fc122b
--- /dev/null
+++ b/test/core/memory_usage/client.c
@@ -0,0 +1,314 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/cmdline.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/support/string.h"
+#include "test/core/util/memory_counters.h"
+#include "test/core/util/test_config.h"
+
+static grpc_channel *channel;
+static grpc_completion_queue *cq;
+static grpc_op metadata_ops[2];
+static grpc_op status_ops[2];
+static grpc_op snapshot_ops[6];
+static grpc_op *op;
+
+typedef struct {
+  grpc_call *call;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_status_code status;
+  char *details;
+  size_t details_capacity;
+  grpc_metadata_array trailing_metadata_recv;
+} fling_call;
+
+// Statically allocate call data structs. Enough to accomodate 10000 ping-pong
+// calls and 1 extra for the snapshot calls.
+static fling_call calls[10001];
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+// A call is intentionally divided into two steps. First step is to initiate a
+// call (i.e send and recv metadata). A call is outstanding after we initated,
+// so we can measure the call memory usage.
+static void init_ping_pong_request(int call_idx) {
+  grpc_metadata_array_init(&calls[call_idx].initial_metadata_recv);
+
+  memset(metadata_ops, 0, sizeof(metadata_ops));
+  op = metadata_ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &calls[call_idx].initial_metadata_recv;
+  op++;
+
+  calls[call_idx].call = grpc_channel_create_call(
+      channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq, "/Reflector/reflectUnary",
+      "localhost", gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(calls[call_idx].call,
+                                                   metadata_ops,
+                                                   (size_t)(op - metadata_ops),
+                                                   tag(call_idx), NULL));
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+}
+
+// Second step is to finish the call (i.e recv status) and destroy the call.
+static void finish_ping_pong_request(int call_idx) {
+  grpc_metadata_array_init(&calls[call_idx].trailing_metadata_recv);
+
+  memset(status_ops, 0, sizeof(status_ops));
+  op = status_ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata =
+      &calls[call_idx].trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &calls[call_idx].status;
+  op->data.recv_status_on_client.status_details = &calls[call_idx].details;
+  op->data.recv_status_on_client.status_details_capacity =
+      &calls[call_idx].details_capacity;
+  op++;
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(calls[call_idx].call,
+                                                   status_ops,
+                                                   (size_t)(op - status_ops),
+                                                   tag(call_idx), NULL));
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  grpc_metadata_array_destroy(&calls[call_idx].initial_metadata_recv);
+  grpc_metadata_array_destroy(&calls[call_idx].trailing_metadata_recv);
+  gpr_free(calls[call_idx].details);
+  grpc_call_destroy(calls[call_idx].call);
+  calls[call_idx].call = NULL;
+}
+
+static struct grpc_memory_counters send_snapshot_request(
+    int call_idx, const char *call_type) {
+  grpc_metadata_array_init(&calls[call_idx].initial_metadata_recv);
+  grpc_metadata_array_init(&calls[call_idx].trailing_metadata_recv);
+
+  grpc_byte_buffer *response_payload_recv = NULL;
+  memset(snapshot_ops, 0, sizeof(snapshot_ops));
+  op = snapshot_ops;
+
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &calls[call_idx].initial_metadata_recv;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata =
+      &calls[call_idx].trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &calls[call_idx].status;
+  op->data.recv_status_on_client.status_details = &calls[call_idx].details;
+  op->data.recv_status_on_client.status_details_capacity =
+      &calls[call_idx].details_capacity;
+  op++;
+
+  calls[call_idx].call = grpc_channel_create_call(
+      channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq, call_type, "localhost",
+      gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(
+                                 calls[call_idx].call, snapshot_ops,
+                                 (size_t)(op - snapshot_ops), (void *)0, NULL));
+  grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+
+  grpc_byte_buffer_reader reader;
+  grpc_byte_buffer_reader_init(&reader, response_payload_recv);
+  grpc_slice response = grpc_byte_buffer_reader_readall(&reader);
+
+  struct grpc_memory_counters snapshot;
+  snapshot.total_size_absolute =
+      ((struct grpc_memory_counters *)GRPC_SLICE_START_PTR(response))
+          ->total_size_absolute;
+  snapshot.total_allocs_absolute =
+      ((struct grpc_memory_counters *)GRPC_SLICE_START_PTR(response))
+          ->total_allocs_absolute;
+  snapshot.total_size_relative =
+      ((struct grpc_memory_counters *)GRPC_SLICE_START_PTR(response))
+          ->total_size_relative;
+  snapshot.total_allocs_relative =
+      ((struct grpc_memory_counters *)GRPC_SLICE_START_PTR(response))
+          ->total_allocs_relative;
+
+  grpc_metadata_array_destroy(&calls[call_idx].initial_metadata_recv);
+  grpc_metadata_array_destroy(&calls[call_idx].trailing_metadata_recv);
+  grpc_slice_unref(response);
+  grpc_byte_buffer_reader_destroy(&reader);
+  grpc_byte_buffer_destroy(response_payload_recv);
+  gpr_free(calls[call_idx].details);
+  calls[call_idx].details = NULL;
+  calls[call_idx].details_capacity = 0;
+  grpc_call_destroy(calls[call_idx].call);
+  calls[call_idx].call = NULL;
+
+  return snapshot;
+}
+
+int main(int argc, char **argv) {
+  grpc_memory_counters_init();
+  grpc_slice slice = grpc_slice_from_copied_string("x");
+  char *fake_argv[1];
+
+  char *target = "localhost:443";
+  gpr_cmdline *cl;
+  grpc_event event;
+
+  grpc_init();
+
+  GPR_ASSERT(argc >= 1);
+  fake_argv[0] = argv[0];
+  grpc_test_init(1, fake_argv);
+
+  int warmup_iterations = 100;
+  int benchmark_iterations = 1000;
+
+  cl = gpr_cmdline_create("memory profiling client");
+  gpr_cmdline_add_string(cl, "target", "Target host:port", &target);
+  gpr_cmdline_add_int(cl, "warmup", "Warmup iterations", &warmup_iterations);
+  gpr_cmdline_add_int(cl, "benchmark", "Benchmark iterations",
+                      &benchmark_iterations);
+  gpr_cmdline_parse(cl, argc, argv);
+  gpr_cmdline_destroy(cl);
+
+  for (int k = 0; k < (int)(sizeof(calls) / sizeof(fling_call)); k++) {
+    calls[k].details = NULL;
+    calls[k].details_capacity = 0;
+  }
+
+  cq = grpc_completion_queue_create(NULL);
+
+  struct grpc_memory_counters client_channel_start =
+      grpc_memory_counters_snapshot();
+  channel = grpc_insecure_channel_create(target, NULL, NULL);
+
+  int call_idx = 0;
+
+  struct grpc_memory_counters before_server_create =
+      send_snapshot_request(0, "Reflector/GetBeforeSvrCreation");
+  struct grpc_memory_counters after_server_create =
+      send_snapshot_request(0, "Reflector/GetAfterSvrCreation");
+
+  // warmup period
+  for (call_idx = 0; call_idx < warmup_iterations; ++call_idx) {
+    init_ping_pong_request(call_idx + 1);
+  }
+
+  struct grpc_memory_counters server_benchmark_calls_start =
+      send_snapshot_request(0, "Reflector/SimpleSnapshot");
+
+  struct grpc_memory_counters client_benchmark_calls_start =
+      grpc_memory_counters_snapshot();
+
+  // benchmark period
+  for (; call_idx < warmup_iterations + benchmark_iterations; ++call_idx) {
+    init_ping_pong_request(call_idx + 1);
+  }
+
+  struct grpc_memory_counters client_calls_inflight =
+      grpc_memory_counters_snapshot();
+
+  struct grpc_memory_counters server_calls_inflight =
+      send_snapshot_request(0, "Reflector/DestroyCalls");
+
+  do {
+    event = grpc_completion_queue_next(
+        cq, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                         gpr_time_from_micros(10000, GPR_TIMESPAN)),
+        NULL);
+  } while (event.type != GRPC_QUEUE_TIMEOUT);
+
+  // second step - recv status and destroy call
+  for (call_idx = 0; call_idx < warmup_iterations + benchmark_iterations;
+       ++call_idx) {
+    finish_ping_pong_request(call_idx + 1);
+  }
+
+  struct grpc_memory_counters server_calls_end =
+      send_snapshot_request(0, "Reflector/SimpleSnapshot");
+
+  struct grpc_memory_counters client_channel_end =
+      grpc_memory_counters_snapshot();
+
+  grpc_channel_destroy(channel);
+  grpc_completion_queue_shutdown(cq);
+
+  do {
+    event = grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME),
+                                       NULL);
+  } while (event.type != GRPC_QUEUE_SHUTDOWN);
+  grpc_slice_unref(slice);
+
+  grpc_completion_queue_destroy(cq);
+  grpc_shutdown();
+
+  gpr_log(GPR_INFO, "---------client stats--------");
+  gpr_log(GPR_INFO, "client call memory usage: %f bytes per call",
+          (double)(client_calls_inflight.total_size_relative -
+                   client_benchmark_calls_start.total_size_relative) /
+              benchmark_iterations);
+  gpr_log(GPR_INFO, "client channel memory usage %zi bytes",
+          client_channel_end.total_size_relative -
+              client_channel_start.total_size_relative);
+
+  gpr_log(GPR_INFO, "---------server stats--------");
+  gpr_log(GPR_INFO, "server create: %zi bytes",
+          after_server_create.total_size_relative -
+              before_server_create.total_size_relative);
+  gpr_log(GPR_INFO, "server call memory usage: %f bytes per call",
+          (double)(server_calls_inflight.total_size_relative -
+                   server_benchmark_calls_start.total_size_relative) /
+              benchmark_iterations);
+  gpr_log(GPR_INFO, "server channel memory usage %zi bytes",
+          server_calls_end.total_size_relative -
+              after_server_create.total_size_relative);
+
+  grpc_memory_counters_destroy();
+  return 0;
+}
diff --git a/test/core/memory_usage/memory_usage_test.c b/test/core/memory_usage/memory_usage_test.c
new file mode 100644
index 0000000..7e7a9d0
--- /dev/null
+++ b/test/core/memory_usage/memory_usage_test.c
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/subprocess.h>
+#include "src/core/lib/support/string.h"
+#include "test/core/util/port.h"
+
+int main(int argc, char **argv) {
+  char *me = argv[0];
+  char *lslash = strrchr(me, '/');
+  char root[1024];
+  int port = grpc_pick_unused_port_or_die();
+  char *args[10];
+  int status;
+  gpr_subprocess *svr, *cli;
+  /* figure out where we are */
+  if (lslash) {
+    memcpy(root, me, (size_t)(lslash - me));
+    root[lslash - me] = 0;
+  } else {
+    strcpy(root, ".");
+  }
+  /* start the server */
+  gpr_asprintf(&args[0], "%s/memory_profile_server%s", root,
+               gpr_subprocess_binary_extension());
+  args[1] = "--bind";
+  gpr_join_host_port(&args[2], "::", port);
+  args[3] = "--no-secure";
+  svr = gpr_subprocess_create(4, (const char **)args);
+  gpr_free(args[0]);
+  gpr_free(args[2]);
+
+  /* start the client */
+  gpr_asprintf(&args[0], "%s/memory_profile_client%s", root,
+               gpr_subprocess_binary_extension());
+  args[1] = "--target";
+  gpr_join_host_port(&args[2], "127.0.0.1", port);
+  args[3] = "--warmup=1000";
+  args[4] = "--benchmark=9000";
+  cli = gpr_subprocess_create(5, (const char **)args);
+  gpr_free(args[0]);
+  gpr_free(args[2]);
+
+  /* wait for completion */
+  printf("waiting for client\n");
+  if ((status = gpr_subprocess_join(cli))) {
+    gpr_subprocess_destroy(cli);
+    gpr_subprocess_destroy(svr);
+    return status;
+  }
+  gpr_subprocess_destroy(cli);
+
+  gpr_subprocess_interrupt(svr);
+  status = gpr_subprocess_join(svr);
+  gpr_subprocess_destroy(svr);
+  return status;
+}
diff --git a/test/core/memory_usage/server.c b/test/core/memory_usage/server.c
new file mode 100644
index 0000000..c071093
--- /dev/null
+++ b/test/core/memory_usage/server.c
@@ -0,0 +1,321 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifndef _WIN32
+/* This is for _exit() below, which is temporary. */
+#include <unistd.h>
+#endif
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/cmdline.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "test/core/end2end/data/ssl_test_data.h"
+#include "test/core/util/memory_counters.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+static grpc_completion_queue *cq;
+static grpc_server *server;
+static grpc_op metadata_ops[2];
+static grpc_op snapshot_ops[5];
+static grpc_op status_op;
+static int got_sigint = 0;
+static grpc_byte_buffer *payload_buffer = NULL;
+static grpc_byte_buffer *terminal_buffer = NULL;
+static int was_cancelled = 2;
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+typedef enum {
+  FLING_SERVER_NEW_REQUEST = 1,
+  FLING_SERVER_SEND_INIT_METADATA,
+  FLING_SERVER_WAIT_FOR_DESTROY,
+  FLING_SERVER_SEND_STATUS_FLING_CALL,
+  FLING_SERVER_SEND_STATUS_SNAPSHOT,
+  FLING_SERVER_BATCH_SEND_STATUS_FLING_CALL
+} fling_server_tags;
+
+typedef struct {
+  fling_server_tags state;
+  grpc_call *call;
+  grpc_call_details call_details;
+  grpc_metadata_array request_metadata_recv;
+  grpc_metadata_array initial_metadata_send;
+} fling_call;
+
+// hold up to 10000 calls and 6 snaphost calls
+static fling_call calls[100006];
+
+static void request_call_unary(int call_idx) {
+  if (call_idx == (int)(sizeof(calls) / sizeof(fling_call))) {
+    gpr_log(GPR_INFO, "Used all call slots (10000) on server. Server exit.");
+    _exit(0);
+  }
+  grpc_metadata_array_init(&calls[call_idx].request_metadata_recv);
+  grpc_server_request_call(
+      server, &calls[call_idx].call, &calls[call_idx].call_details,
+      &calls[call_idx].request_metadata_recv, cq, cq, &calls[call_idx]);
+}
+
+static void send_initial_metadata_unary(void *tag) {
+  grpc_metadata_array_init(&(*(fling_call *)tag).initial_metadata_send);
+  metadata_ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
+  metadata_ops[0].data.send_initial_metadata.count = 0;
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch((*(fling_call *)tag).call,
+                                                   metadata_ops, 1, tag, NULL));
+}
+
+static void send_status(void *tag) {
+  status_op.op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  status_op.data.send_status_from_server.status = GRPC_STATUS_OK;
+  status_op.data.send_status_from_server.trailing_metadata_count = 0;
+  status_op.data.send_status_from_server.status_details = "";
+
+  GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch((*(fling_call *)tag).call,
+                                                   &status_op, 1, tag, NULL));
+}
+
+static void send_snapshot(void *tag, struct grpc_memory_counters *snapshot) {
+  grpc_op *op;
+
+  grpc_slice snapshot_slice =
+      grpc_slice_new(snapshot, sizeof(*snapshot), gpr_free);
+  payload_buffer = grpc_raw_byte_buffer_create(&snapshot_slice, 1);
+  grpc_metadata_array_init(&(*(fling_call *)tag).initial_metadata_send);
+
+  op = snapshot_ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &terminal_buffer;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  if (payload_buffer == NULL) {
+    gpr_log(GPR_INFO, "NULL payload buffer !!!");
+  }
+  op->data.send_message = payload_buffer;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status_details = "";
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+
+  GPR_ASSERT(GRPC_CALL_OK ==
+             grpc_call_start_batch((*(fling_call *)tag).call, snapshot_ops,
+                                   (size_t)(op - snapshot_ops), tag, NULL));
+}
+/* We have some sort of deadlock, so let's not exit gracefully for now.
+   When that is resolved, please remove the #include <unistd.h> above. */
+static void sigint_handler(int x) { _exit(0); }
+
+int main(int argc, char **argv) {
+  grpc_memory_counters_init();
+  grpc_event ev;
+  char *addr_buf = NULL;
+  gpr_cmdline *cl;
+  int shutdown_started = 0;
+  int shutdown_finished = 0;
+
+  int secure = 0;
+  char *addr = NULL;
+
+  char *fake_argv[1];
+
+  GPR_ASSERT(argc >= 1);
+  fake_argv[0] = argv[0];
+  grpc_test_init(1, fake_argv);
+
+  grpc_init();
+  srand((unsigned)clock());
+
+  cl = gpr_cmdline_create("fling server");
+  gpr_cmdline_add_string(cl, "bind", "Bind host:port", &addr);
+  gpr_cmdline_add_flag(cl, "secure", "Run with security?", &secure);
+  gpr_cmdline_parse(cl, argc, argv);
+  gpr_cmdline_destroy(cl);
+
+  if (addr == NULL) {
+    gpr_join_host_port(&addr_buf, "::", grpc_pick_unused_port_or_die());
+    addr = addr_buf;
+  }
+  gpr_log(GPR_INFO, "creating server on: %s", addr);
+
+  cq = grpc_completion_queue_create(NULL);
+
+  struct grpc_memory_counters before_server_create =
+      grpc_memory_counters_snapshot();
+  if (secure) {
+    grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
+                                                    test_server1_cert};
+    grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(
+        NULL, &pem_key_cert_pair, 1, 0, NULL);
+    server = grpc_server_create(NULL, NULL);
+    GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, ssl_creds));
+    grpc_server_credentials_release(ssl_creds);
+  } else {
+    server = grpc_server_create(NULL, NULL);
+    GPR_ASSERT(grpc_server_add_insecure_http2_port(server, addr));
+  }
+
+  grpc_server_register_completion_queue(server, cq, NULL);
+  grpc_server_start(server);
+
+  struct grpc_memory_counters after_server_create =
+      grpc_memory_counters_snapshot();
+
+  gpr_free(addr_buf);
+  addr = addr_buf = NULL;
+
+  // initialize call instances
+  for (int i = 0; i < (int)(sizeof(calls) / sizeof(fling_call)); i++) {
+    grpc_call_details_init(&calls[i].call_details);
+    calls[i].state = FLING_SERVER_NEW_REQUEST;
+  }
+
+  int next_call_idx = 0;
+  struct grpc_memory_counters current_snapshot;
+
+  request_call_unary(next_call_idx);
+
+  signal(SIGINT, sigint_handler);
+
+  while (!shutdown_finished) {
+    if (got_sigint && !shutdown_started) {
+      gpr_log(GPR_INFO, "Shutting down due to SIGINT");
+      grpc_server_shutdown_and_notify(server, cq, tag(1000));
+      GPR_ASSERT(grpc_completion_queue_pluck(
+                     cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                     .type == GRPC_OP_COMPLETE);
+      grpc_completion_queue_shutdown(cq);
+      shutdown_started = 1;
+    }
+    ev = grpc_completion_queue_next(
+        cq, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                         gpr_time_from_micros(1000000, GPR_TIMESPAN)),
+        NULL);
+    fling_call *s = ev.tag;
+    switch (ev.type) {
+      case GRPC_OP_COMPLETE:
+        switch (s->state) {
+          case FLING_SERVER_NEW_REQUEST:
+            request_call_unary(++next_call_idx);
+            if (0 ==
+                strcmp(s->call_details.method, "/Reflector/reflectUnary")) {
+              s->state = FLING_SERVER_SEND_INIT_METADATA;
+              send_initial_metadata_unary(s);
+            } else if (0 == strcmp(s->call_details.method,
+                                   "Reflector/GetBeforeSvrCreation")) {
+              s->state = FLING_SERVER_SEND_STATUS_SNAPSHOT;
+              send_snapshot(s, &before_server_create);
+            } else if (0 == strcmp(s->call_details.method,
+                                   "Reflector/GetAfterSvrCreation")) {
+              s->state = FLING_SERVER_SEND_STATUS_SNAPSHOT;
+              send_snapshot(s, &after_server_create);
+            } else if (0 == strcmp(s->call_details.method,
+                                   "Reflector/SimpleSnapshot")) {
+              s->state = FLING_SERVER_SEND_STATUS_SNAPSHOT;
+              current_snapshot = grpc_memory_counters_snapshot();
+              send_snapshot(s, &current_snapshot);
+            } else if (0 == strcmp(s->call_details.method,
+                                   "Reflector/DestroyCalls")) {
+              s->state = FLING_SERVER_BATCH_SEND_STATUS_FLING_CALL;
+              current_snapshot = grpc_memory_counters_snapshot();
+              send_snapshot(s, &current_snapshot);
+            } else {
+              gpr_log(GPR_ERROR, "Wrong call method");
+            }
+            break;
+          case FLING_SERVER_SEND_INIT_METADATA:
+            s->state = FLING_SERVER_WAIT_FOR_DESTROY;
+            break;
+          case FLING_SERVER_WAIT_FOR_DESTROY:
+            break;
+          case FLING_SERVER_SEND_STATUS_FLING_CALL:
+            grpc_call_destroy(s->call);
+            grpc_call_details_destroy(&s->call_details);
+            grpc_metadata_array_destroy(&s->initial_metadata_send);
+            grpc_metadata_array_destroy(&s->request_metadata_recv);
+            break;
+          case FLING_SERVER_BATCH_SEND_STATUS_FLING_CALL:
+            for (int k = 0; k < (int)(sizeof(calls) / sizeof(fling_call));
+                 ++k) {
+              if (calls[k].state == FLING_SERVER_WAIT_FOR_DESTROY) {
+                calls[k].state = FLING_SERVER_SEND_STATUS_FLING_CALL;
+                send_status(&calls[k]);
+              }
+            }
+          // no break here since we want to continue to case
+          // FLING_SERVER_SEND_STATUS_SNAPSHOT to destroy the snapshot call
+          case FLING_SERVER_SEND_STATUS_SNAPSHOT:
+            grpc_byte_buffer_destroy(payload_buffer);
+            grpc_byte_buffer_destroy(terminal_buffer);
+            grpc_call_destroy(s->call);
+            grpc_call_details_destroy(&s->call_details);
+            grpc_metadata_array_destroy(&s->initial_metadata_send);
+            grpc_metadata_array_destroy(&s->request_metadata_recv);
+            terminal_buffer = NULL;
+            payload_buffer = NULL;
+            break;
+        }
+        break;
+      case GRPC_QUEUE_SHUTDOWN:
+        GPR_ASSERT(shutdown_started);
+        shutdown_finished = 1;
+        break;
+      case GRPC_QUEUE_TIMEOUT:
+        break;
+    }
+  }
+
+  grpc_server_destroy(server);
+  grpc_completion_queue_destroy(cq);
+  grpc_shutdown();
+  grpc_memory_counters_destroy();
+  return 0;
+}
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/core/nanopb/BUILD
old mode 100755
new mode 100644
similarity index 76%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/core/nanopb/BUILD
index 7438713..bdf79b7
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/core/nanopb/BUILD
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,21 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cd $(dirname $0)/../..
+grpc_fuzzer(
+  name = "fuzzer_response",
+  srcs = ["fuzzer_response.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "corpus_response",
+  copts = ["-std=c99"],
+)
 
-make grpc_csharp_ext
+grpc_fuzzer(
+  name = "fuzzer_serverlist",
+  srcs = ["fuzzer_serverlist.c"],
+  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "corpus_serverlist",
+  copts = ["-std=c99"],
+)
 
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
diff --git a/test/core/security/b64_test.c b/test/core/security/b64_test.c
index af883f5..28af480 100644
--- a/test/core/security/b64_test.c
+++ b/test/core/security/b64_test.c
@@ -38,6 +38,8 @@
 #include <grpc/slice.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
 static int buffers_are_equal(const unsigned char *buf1,
@@ -57,12 +59,14 @@
   const char *hello = "hello";
   char *hello_b64 =
       grpc_base64_encode(hello, strlen(hello), url_safe, multiline);
-  grpc_slice hello_slice = grpc_base64_decode(hello_b64, url_safe);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_slice hello_slice = grpc_base64_decode(&exec_ctx, hello_b64, url_safe);
   GPR_ASSERT(GRPC_SLICE_LENGTH(hello_slice) == strlen(hello));
   GPR_ASSERT(strncmp((const char *)GRPC_SLICE_START_PTR(hello_slice), hello,
                      GRPC_SLICE_LENGTH(hello_slice)) == 0);
 
-  grpc_slice_unref(hello_slice);
+  grpc_slice_unref_internal(&exec_ctx, hello_slice);
+  grpc_exec_ctx_finish(&exec_ctx);
   gpr_free(hello_b64);
 }
 
@@ -75,13 +79,15 @@
 
   /* Try all the different paddings. */
   for (i = 0; i < 3; i++) {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     b64 = grpc_base64_encode(orig, sizeof(orig) - i, url_safe, multiline);
-    orig_decoded = grpc_base64_decode(b64, url_safe);
+    orig_decoded = grpc_base64_decode(&exec_ctx, b64, url_safe);
     GPR_ASSERT(GRPC_SLICE_LENGTH(orig_decoded) == (sizeof(orig) - i));
     GPR_ASSERT(buffers_are_equal(orig, GRPC_SLICE_START_PTR(orig_decoded),
                                  sizeof(orig) - i));
-    grpc_slice_unref(orig_decoded);
+    grpc_slice_unref_internal(&exec_ctx, orig_decoded);
     gpr_free(b64);
+    grpc_exec_ctx_finish(&exec_ctx);
   }
 }
 
@@ -117,7 +123,7 @@
   test_full_range_encode_decode_b64(1, 1);
 }
 
-static void test_url_safe_unsafe_mismtach_failure(void) {
+static void test_url_safe_unsafe_mismatch_failure(void) {
   unsigned char orig[256];
   size_t i;
   char *b64;
@@ -125,17 +131,19 @@
   int url_safe = 1;
   for (i = 0; i < sizeof(orig); i++) orig[i] = (uint8_t)i;
 
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   b64 = grpc_base64_encode(orig, sizeof(orig), url_safe, 0);
-  orig_decoded = grpc_base64_decode(b64, !url_safe);
+  orig_decoded = grpc_base64_decode(&exec_ctx, b64, !url_safe);
   GPR_ASSERT(GRPC_SLICE_IS_EMPTY(orig_decoded));
   gpr_free(b64);
-  grpc_slice_unref(orig_decoded);
+  grpc_slice_unref_internal(&exec_ctx, orig_decoded);
 
   b64 = grpc_base64_encode(orig, sizeof(orig), !url_safe, 0);
-  orig_decoded = grpc_base64_decode(b64, url_safe);
+  orig_decoded = grpc_base64_decode(&exec_ctx, b64, url_safe);
   GPR_ASSERT(GRPC_SLICE_IS_EMPTY(orig_decoded));
   gpr_free(b64);
-  grpc_slice_unref(orig_decoded);
+  grpc_slice_unref_internal(&exec_ctx, orig_decoded);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_rfc4648_test_vectors(void) {
@@ -173,38 +181,40 @@
 static void test_unpadded_decode(void) {
   grpc_slice decoded;
 
-  decoded = grpc_base64_decode("Zm9vYmFy", 0);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  decoded = grpc_base64_decode(&exec_ctx, "Zm9vYmFy", 0);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(decoded));
   GPR_ASSERT(grpc_slice_str_cmp(decoded, "foobar") == 0);
   grpc_slice_unref(decoded);
 
-  decoded = grpc_base64_decode("Zm9vYmE", 0);
+  decoded = grpc_base64_decode(&exec_ctx, "Zm9vYmE", 0);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(decoded));
   GPR_ASSERT(grpc_slice_str_cmp(decoded, "fooba") == 0);
   grpc_slice_unref(decoded);
 
-  decoded = grpc_base64_decode("Zm9vYg", 0);
+  decoded = grpc_base64_decode(&exec_ctx, "Zm9vYg", 0);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(decoded));
   GPR_ASSERT(grpc_slice_str_cmp(decoded, "foob") == 0);
   grpc_slice_unref(decoded);
 
-  decoded = grpc_base64_decode("Zm9v", 0);
+  decoded = grpc_base64_decode(&exec_ctx, "Zm9v", 0);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(decoded));
   GPR_ASSERT(grpc_slice_str_cmp(decoded, "foo") == 0);
   grpc_slice_unref(decoded);
 
-  decoded = grpc_base64_decode("Zm8", 0);
+  decoded = grpc_base64_decode(&exec_ctx, "Zm8", 0);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(decoded));
   GPR_ASSERT(grpc_slice_str_cmp(decoded, "fo") == 0);
   grpc_slice_unref(decoded);
 
-  decoded = grpc_base64_decode("Zg", 0);
+  decoded = grpc_base64_decode(&exec_ctx, "Zg", 0);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(decoded));
   GPR_ASSERT(grpc_slice_str_cmp(decoded, "f") == 0);
   grpc_slice_unref(decoded);
 
-  decoded = grpc_base64_decode("", 0);
+  decoded = grpc_base64_decode(&exec_ctx, "", 0);
   GPR_ASSERT(GRPC_SLICE_IS_EMPTY(decoded));
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int main(int argc, char **argv) {
@@ -217,7 +227,7 @@
   test_full_range_encode_decode_b64_multiline();
   test_full_range_encode_decode_b64_urlsafe_no_multiline();
   test_full_range_encode_decode_b64_urlsafe_multiline();
-  test_url_safe_unsafe_mismtach_failure();
+  test_url_safe_unsafe_mismatch_failure();
   test_rfc4648_test_vectors();
   test_unpadded_decode();
   return 0;
diff --git a/test/core/security/create_jwt.c b/test/core/security/create_jwt.c
index 741ace9..ac795f2 100644
--- a/test/core/security/create_jwt.c
+++ b/test/core/security/create_jwt.c
@@ -72,6 +72,7 @@
   char *scope = NULL;
   char *json_key_file_path = NULL;
   char *service_url = NULL;
+  grpc_init();
   gpr_cmdline *cl = gpr_cmdline_create("create_jwt");
   gpr_cmdline_add_string(cl, "json_key", "File path of the json key.",
                          &json_key_file_path);
@@ -102,5 +103,6 @@
   create_jwt(json_key_file_path, service_url, scope);
 
   gpr_cmdline_destroy(cl);
+  grpc_shutdown();
   return 0;
 }
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index d4c7550..0a79292 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -166,24 +166,29 @@
 /* -- Tests. -- */
 
 static void test_empty_md_store(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(0);
   GPR_ASSERT(store->num_entries == 0);
   GPR_ASSERT(store->allocated == 0);
-  grpc_credentials_md_store_unref(store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_ref_unref_empty_md_store(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(0);
   grpc_credentials_md_store_ref(store);
   grpc_credentials_md_store_ref(store);
   GPR_ASSERT(store->num_entries == 0);
   GPR_ASSERT(store->allocated == 0);
-  grpc_credentials_md_store_unref(store);
-  grpc_credentials_md_store_unref(store);
-  grpc_credentials_md_store_unref(store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_add_to_empty_md_store(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(0);
   const char *key_str = "hello";
   const char *value_str = "there blah blah blah blah blah blah blah";
@@ -195,10 +200,12 @@
   GPR_ASSERT(grpc_slice_cmp(value, store->entries[0].value) == 0);
   grpc_slice_unref(key);
   grpc_slice_unref(value);
-  grpc_credentials_md_store_unref(store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_add_cstrings_to_empty_md_store(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(0);
   const char *key_str = "hello";
   const char *value_str = "there blah blah blah blah blah blah blah";
@@ -206,18 +213,22 @@
   GPR_ASSERT(store->num_entries == 1);
   GPR_ASSERT(grpc_slice_str_cmp(store->entries[0].key, key_str) == 0);
   GPR_ASSERT(grpc_slice_str_cmp(store->entries[0].value, value_str) == 0);
-  grpc_credentials_md_store_unref(store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_empty_preallocated_md_store(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(4);
   GPR_ASSERT(store->num_entries == 0);
   GPR_ASSERT(store->allocated == 4);
   GPR_ASSERT(store->entries != NULL);
-  grpc_credentials_md_store_unref(store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_add_abunch_to_md_store(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(4);
   size_t num_entries = 1000;
   const char *key_str = "hello";
@@ -230,16 +241,19 @@
     GPR_ASSERT(grpc_slice_str_cmp(store->entries[i].key, key_str) == 0);
     GPR_ASSERT(grpc_slice_str_cmp(store->entries[i].value, value_str) == 0);
   }
-  grpc_credentials_md_store_unref(store);
+  grpc_credentials_md_store_unref(&exec_ctx, store);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_ok(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response =
       http_response(200, valid_oauth2_json_response);
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) == GRPC_CREDENTIALS_OK);
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
+             GRPC_CREDENTIALS_OK);
   GPR_ASSERT(token_lifetime.tv_sec == 3599);
   GPR_ASSERT(token_lifetime.tv_nsec == 0);
   GPR_ASSERT(token_md->num_entries == 1);
@@ -248,32 +262,38 @@
   GPR_ASSERT(grpc_slice_str_cmp(token_md->entries[0].value,
                                 "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") ==
              0);
-  grpc_credentials_md_store_unref(token_md);
+  grpc_credentials_md_store_unref(&exec_ctx, token_md);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response =
       http_response(401, valid_oauth2_json_response);
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_ERROR);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response = http_response(200, "");
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_ERROR);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response =
@@ -282,12 +302,14 @@
                     " \"expires_in\":3599, "
                     " \"token_type\":\"Bearer\"");
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_ERROR);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response = http_response(200,
@@ -295,12 +317,14 @@
                                                  " \"expires_in\":3599, "
                                                  " \"token_type\":\"Bearer\"}");
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_ERROR);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response =
@@ -309,13 +333,15 @@
                     " \"expires_in\":3599, "
                     "}");
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_ERROR);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime(
     void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_credentials_md_store *token_md = NULL;
   gpr_timespec token_lifetime;
   grpc_httpcli_response response =
@@ -323,9 +349,10 @@
                     "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\","
                     " \"token_type\":\"Bearer\"}");
   GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response(
-                 &response, &token_md, &token_lifetime) ==
+                 &exec_ctx, &response, &token_md, &token_lifetime) ==
              GRPC_CREDENTIALS_ERROR);
   grpc_http_response_destroy(&response);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void check_metadata(expected_md *expected, grpc_credentials_md *md_elems,
@@ -361,7 +388,7 @@
   GPR_ASSERT(error_details == NULL);
   GPR_ASSERT(num_md == 2);
   check_metadata(emd, md_elems, num_md);
-  grpc_call_credentials_unref(c);
+  grpc_call_credentials_unref(exec_ctx, c);
 }
 
 static void test_google_iam_creds(void) {
@@ -385,7 +412,7 @@
   GPR_ASSERT(error_details == NULL);
   GPR_ASSERT(num_md == 1);
   check_metadata(emd, md_elems, num_md);
-  grpc_call_credentials_unref(c);
+  grpc_call_credentials_unref(exec_ctx, c);
 }
 
 static void test_access_token_creds(void) {
@@ -401,9 +428,10 @@
 }
 
 static grpc_security_status check_channel_oauth2_create_security_connector(
-    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c,
+    grpc_call_credentials *call_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
   GPR_ASSERT(strcmp(c->type, "mock") == 0);
   GPR_ASSERT(call_creds != NULL);
   GPR_ASSERT(strcmp(call_creds->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
@@ -411,6 +439,7 @@
 }
 
 static void test_channel_oauth2_composite_creds(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_channel_args *new_args;
   grpc_channel_credentials_vtable vtable = {
       NULL, check_channel_oauth2_create_security_connector, NULL};
@@ -424,9 +453,10 @@
   grpc_channel_credentials_release(channel_creds);
   grpc_call_credentials_release(oauth2_creds);
   GPR_ASSERT(grpc_channel_credentials_create_security_connector(
-                 channel_oauth2_creds, NULL, NULL, NULL, &new_args) ==
-             GRPC_SECURITY_OK);
+                 &exec_ctx, channel_oauth2_creds, NULL, NULL, NULL,
+                 &new_args) == GRPC_SECURITY_OK);
   grpc_channel_credentials_release(channel_oauth2_creds);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void check_oauth2_google_iam_composite_metadata(
@@ -443,7 +473,7 @@
   GPR_ASSERT(error_details == NULL);
   GPR_ASSERT(num_md == 3);
   check_metadata(emd, md_elems, num_md);
-  grpc_call_credentials_unref(c);
+  grpc_call_credentials_unref(exec_ctx, c);
 }
 
 static void test_oauth2_google_iam_composite_creds(void) {
@@ -459,8 +489,8 @@
   grpc_call_credentials *composite_creds =
       grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds,
                                              NULL);
-  grpc_call_credentials_unref(oauth2_creds);
-  grpc_call_credentials_unref(google_iam_creds);
+  grpc_call_credentials_unref(&exec_ctx, oauth2_creds);
+  grpc_call_credentials_unref(&exec_ctx, google_iam_creds);
   GPR_ASSERT(
       strcmp(composite_creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
   creds_array =
@@ -478,9 +508,10 @@
 
 static grpc_security_status
 check_channel_oauth2_google_iam_create_security_connector(
-    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
-    const char *target, const grpc_channel_args *args,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+    grpc_exec_ctx *exec_ctx, grpc_channel_credentials *c,
+    grpc_call_credentials *call_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
   const grpc_call_credentials_array *creds_array;
   GPR_ASSERT(strcmp(c->type, "mock") == 0);
   GPR_ASSERT(call_creds != NULL);
@@ -495,6 +526,7 @@
 }
 
 static void test_channel_oauth2_google_iam_composite_creds(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_channel_args *new_args;
   grpc_channel_credentials_vtable vtable = {
       NULL, check_channel_oauth2_google_iam_create_security_connector, NULL};
@@ -517,10 +549,11 @@
   grpc_call_credentials_release(google_iam_creds);
 
   GPR_ASSERT(grpc_channel_credentials_create_security_connector(
-                 channel_oauth2_iam_creds, NULL, NULL, NULL, &new_args) ==
-             GRPC_SECURITY_OK);
+                 &exec_ctx, channel_oauth2_iam_creds, NULL, NULL, NULL,
+                 &new_args) == GRPC_SECURITY_OK);
 
   grpc_channel_credentials_release(channel_oauth2_iam_creds);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void on_oauth2_creds_get_metadata_success(
@@ -565,7 +598,7 @@
     grpc_httpcli_response *response) {
   validate_compute_engine_http_request(request);
   *response = http_response(200, valid_oauth2_json_response);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -575,7 +608,7 @@
     grpc_httpcli_response *response) {
   validate_compute_engine_http_request(request);
   *response = http_response(403, "Not Authorized.");
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -619,7 +652,7 @@
       on_oauth2_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_finish(&exec_ctx);
 
-  grpc_call_credentials_unref(compute_engine_creds);
+  grpc_call_credentials_unref(&exec_ctx, compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
 }
 
@@ -634,7 +667,7 @@
   grpc_call_credentials_get_request_metadata(
       &exec_ctx, compute_engine_creds, NULL, auth_md_ctx,
       on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
-  grpc_call_credentials_unref(compute_engine_creds);
+  grpc_call_credentials_unref(&exec_ctx, compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -668,7 +701,7 @@
     grpc_closure *on_done, grpc_httpcli_response *response) {
   validate_refresh_token_http_request(request, body, body_size);
   *response = http_response(200, valid_oauth2_json_response);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -678,7 +711,7 @@
     grpc_closure *on_done, grpc_httpcli_response *response) {
   validate_refresh_token_http_request(request, body, body_size);
   *response = http_response(403, "Not Authorized.");
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -706,7 +739,7 @@
       on_oauth2_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
 
-  grpc_call_credentials_unref(refresh_token_creds);
+  grpc_call_credentials_unref(&exec_ctx, refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -723,7 +756,7 @@
   grpc_call_credentials_get_request_metadata(
       &exec_ctx, refresh_token_creds, NULL, auth_md_ctx,
       on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
-  grpc_call_credentials_unref(refresh_token_creds);
+  grpc_call_credentials_unref(&exec_ctx, refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -832,7 +865,7 @@
   grpc_exec_ctx_flush(&exec_ctx);
 
   gpr_free(json_key_string);
-  grpc_call_credentials_unref(jwt_creds);
+  grpc_call_credentials_unref(&exec_ctx, jwt_creds);
   grpc_jwt_encode_and_sign_set_override(NULL);
 }
 
@@ -851,7 +884,7 @@
       on_jwt_creds_get_metadata_failure, (void *)test_user_data);
 
   gpr_free(json_key_string);
-  grpc_call_credentials_unref(jwt_creds);
+  grpc_call_credentials_unref(&exec_ctx, jwt_creds);
   grpc_jwt_encode_and_sign_set_override(NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -870,6 +903,7 @@
 }
 
 static void test_google_default_creds_auth_key(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_service_account_jwt_access_credentials *jwt;
   grpc_composite_channel_credentials *creds;
   char *json_key = test_json_key_str();
@@ -885,11 +919,13 @@
       strcmp(jwt->key.client_id,
              "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
       0);
-  grpc_channel_credentials_unref(&creds->base);
+  grpc_channel_credentials_unref(&exec_ctx, &creds->base);
   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_google_default_creds_refresh_token(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_google_refresh_token_credentials *refresh;
   grpc_composite_channel_credentials *creds;
   grpc_flush_cached_google_default_credentials();
@@ -901,8 +937,9 @@
   refresh = (grpc_google_refresh_token_credentials *)creds->call_creds;
   GPR_ASSERT(strcmp(refresh->refresh_token.client_id,
                     "32555999999.apps.googleusercontent.com") == 0);
-  grpc_channel_credentials_unref(&creds->base);
+  grpc_channel_credentials_unref(&exec_ctx, &creds->base);
   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static int default_creds_gce_detection_httpcli_get_success_override(
@@ -917,7 +954,7 @@
   response->hdrs = headers;
   GPR_ASSERT(strcmp(request->http.path, "/") == 0);
   GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -975,7 +1012,7 @@
   GPR_ASSERT(strcmp(request->http.path, "/") == 0);
   GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
   *response = http_response(200, "");
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -1142,6 +1179,8 @@
 }
 
 static void test_channel_creds_duplicate_without_call_creds(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
   grpc_channel_credentials *channel_creds =
       grpc_fake_transport_security_credentials_create();
 
@@ -1149,21 +1188,23 @@
       grpc_channel_credentials_duplicate_without_call_credentials(
           channel_creds);
   GPR_ASSERT(dup == channel_creds);
-  grpc_channel_credentials_unref(dup);
+  grpc_channel_credentials_unref(&exec_ctx, dup);
 
   grpc_call_credentials *call_creds =
       grpc_access_token_credentials_create("blah", NULL);
   grpc_channel_credentials *composite_creds =
       grpc_composite_channel_credentials_create(channel_creds, call_creds,
                                                 NULL);
-  grpc_call_credentials_unref(call_creds);
+  grpc_call_credentials_unref(&exec_ctx, call_creds);
   dup = grpc_channel_credentials_duplicate_without_call_credentials(
       composite_creds);
   GPR_ASSERT(dup == channel_creds);
-  grpc_channel_credentials_unref(dup);
+  grpc_channel_credentials_unref(&exec_ctx, dup);
 
-  grpc_channel_credentials_unref(channel_creds);
-  grpc_channel_credentials_unref(composite_creds);
+  grpc_channel_credentials_unref(&exec_ctx, channel_creds);
+  grpc_channel_credentials_unref(&exec_ctx, composite_creds);
+
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c
index 2016558..5cebb09 100644
--- a/test/core/security/json_token_test.c
+++ b/test/core/security/json_token_test.c
@@ -44,6 +44,7 @@
 #include "src/core/lib/json/json.h"
 #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h"
 #include "src/core/lib/security/util/b64.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "test/core/util/test_config.h"
 
 /* This JSON key was generated with the GCE console and revoked immediately.
@@ -220,6 +221,7 @@
 
 static grpc_json *parse_json_part_from_jwt(const char *str, size_t len,
                                            char **scratchpad) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   char *b64;
   char *decoded;
   grpc_json *json;
@@ -227,7 +229,7 @@
   b64 = gpr_malloc(len + 1);
   strncpy(b64, str, len);
   b64[len] = '\0';
-  slice = grpc_base64_decode(b64, 1);
+  slice = grpc_base64_decode(&exec_ctx, b64, 1);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(slice));
   decoded = gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1);
   strncpy(decoded, (const char *)GRPC_SLICE_START_PTR(slice),
@@ -237,6 +239,7 @@
   gpr_free(b64);
   *scratchpad = decoded;
   grpc_slice_unref(slice);
+  grpc_exec_ctx_finish(&exec_ctx);
   return json;
 }
 
@@ -338,10 +341,12 @@
 static void check_jwt_signature(const char *b64_signature, RSA *rsa_key,
                                 const char *signed_data,
                                 size_t signed_data_size) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
   EVP_MD_CTX *md_ctx = EVP_MD_CTX_create();
   EVP_PKEY *key = EVP_PKEY_new();
 
-  grpc_slice sig = grpc_base64_decode(b64_signature, 1);
+  grpc_slice sig = grpc_base64_decode(&exec_ctx, b64_signature, 1);
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(sig));
   GPR_ASSERT(GRPC_SLICE_LENGTH(sig) == 128);
 
@@ -355,9 +360,11 @@
   GPR_ASSERT(EVP_DigestVerifyFinal(md_ctx, GRPC_SLICE_START_PTR(sig),
                                    GRPC_SLICE_LENGTH(sig)) == 1);
 
-  grpc_slice_unref(sig);
+  grpc_slice_unref_internal(&exec_ctx, sig);
   if (key != NULL) EVP_PKEY_free(key);
   if (md_ctx != NULL) EVP_MD_CTX_destroy(md_ctx);
+
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static char *service_account_creds_jwt_encode_and_sign(
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
index f8afba8..a9bd976 100644
--- a/test/core/security/jwt_verifier_test.c
+++ b/test/core/security/jwt_verifier_test.c
@@ -166,6 +166,13 @@
     "  \"jti\": \"jwtuniqueid\","
     "  \"foo\": \"bar\"}";
 
+static const char claims_with_bad_subject[] =
+    "{ \"aud\": \"https://foo.com\","
+    "  \"iss\": \"evil@blah.foo.com\","
+    "  \"sub\": \"juju@blah.foo.com\","
+    "  \"jti\": \"jwtuniqueid\","
+    "  \"foo\": \"bar\"}";
+
 static const char invalid_claims[] =
     "{ \"aud\": \"https://foo.com\","
     "  \"iss\": 46," /* Issuer cannot be a number. */
@@ -179,13 +186,46 @@
   const char *expected_subject;
 } verifier_test_config;
 
+static void test_jwt_issuer_email_domain(void) {
+  const char *d = grpc_jwt_issuer_email_domain("https://foo.com");
+  GPR_ASSERT(d == NULL);
+  d = grpc_jwt_issuer_email_domain("foo.com");
+  GPR_ASSERT(d == NULL);
+  d = grpc_jwt_issuer_email_domain("");
+  GPR_ASSERT(d == NULL);
+  d = grpc_jwt_issuer_email_domain("@");
+  GPR_ASSERT(d == NULL);
+  d = grpc_jwt_issuer_email_domain("bar@foo");
+  GPR_ASSERT(strcmp(d, "foo") == 0);
+  d = grpc_jwt_issuer_email_domain("bar@foo.com");
+  GPR_ASSERT(strcmp(d, "foo.com") == 0);
+  d = grpc_jwt_issuer_email_domain("bar@blah.foo.com");
+  GPR_ASSERT(strcmp(d, "foo.com") == 0);
+  d = grpc_jwt_issuer_email_domain("bar.blah@blah.foo.com");
+  GPR_ASSERT(strcmp(d, "foo.com") == 0);
+  d = grpc_jwt_issuer_email_domain("bar.blah@baz.blah.foo.com");
+  GPR_ASSERT(strcmp(d, "foo.com") == 0);
+
+  /* This is not a very good parser but make sure we do not crash on these weird
+     inputs. */
+  d = grpc_jwt_issuer_email_domain("@foo");
+  GPR_ASSERT(strcmp(d, "foo") == 0);
+  d = grpc_jwt_issuer_email_domain("bar@.");
+  GPR_ASSERT(d != NULL);
+  d = grpc_jwt_issuer_email_domain("bar@..");
+  GPR_ASSERT(d != NULL);
+  d = grpc_jwt_issuer_email_domain("bar@...");
+  GPR_ASSERT(d != NULL);
+}
+
 static void test_claims_success(void) {
   grpc_jwt_claims *claims;
   grpc_slice s = grpc_slice_from_copied_string(claims_without_time_constraint);
   grpc_json *json = grpc_json_parse_string_with_len(
       (char *)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   GPR_ASSERT(json != NULL);
-  claims = grpc_jwt_claims_from_json(json, s);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  claims = grpc_jwt_claims_from_json(&exec_ctx, json, s);
   GPR_ASSERT(claims != NULL);
   GPR_ASSERT(grpc_jwt_claims_json(claims) == json);
   GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0);
@@ -194,7 +234,8 @@
   GPR_ASSERT(strcmp(grpc_jwt_claims_id(claims), "jwtuniqueid") == 0);
   GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
              GRPC_JWT_VERIFIER_OK);
-  grpc_jwt_claims_destroy(claims);
+  grpc_jwt_claims_destroy(&exec_ctx, claims);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_expired_claims_failure(void) {
@@ -206,7 +247,8 @@
   gpr_timespec exp_exp = {120, 0, GPR_CLOCK_REALTIME};
   gpr_timespec exp_nbf = {60, 0, GPR_CLOCK_REALTIME};
   GPR_ASSERT(json != NULL);
-  claims = grpc_jwt_claims_from_json(json, s);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  claims = grpc_jwt_claims_from_json(&exec_ctx, json, s);
   GPR_ASSERT(claims != NULL);
   GPR_ASSERT(grpc_jwt_claims_json(claims) == json);
   GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), "https://foo.com") == 0);
@@ -219,14 +261,17 @@
 
   GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
              GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE);
-  grpc_jwt_claims_destroy(claims);
+  grpc_jwt_claims_destroy(&exec_ctx, claims);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_invalid_claims_failure(void) {
   grpc_slice s = grpc_slice_from_copied_string(invalid_claims);
   grpc_json *json = grpc_json_parse_string_with_len(
       (char *)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
-  GPR_ASSERT(grpc_jwt_claims_from_json(json, s) == NULL);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GPR_ASSERT(grpc_jwt_claims_from_json(&exec_ctx, json, s) == NULL);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_bad_audience_claims_failure(void) {
@@ -235,11 +280,28 @@
   grpc_json *json = grpc_json_parse_string_with_len(
       (char *)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
   GPR_ASSERT(json != NULL);
-  claims = grpc_jwt_claims_from_json(json, s);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  claims = grpc_jwt_claims_from_json(&exec_ctx, json, s);
   GPR_ASSERT(claims != NULL);
   GPR_ASSERT(grpc_jwt_claims_check(claims, "https://bar.com") ==
              GRPC_JWT_VERIFIER_BAD_AUDIENCE);
-  grpc_jwt_claims_destroy(claims);
+  grpc_jwt_claims_destroy(&exec_ctx, claims);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_bad_subject_claims_failure(void) {
+  grpc_jwt_claims *claims;
+  grpc_slice s = grpc_slice_from_copied_string(claims_with_bad_subject);
+  grpc_json *json = grpc_json_parse_string_with_len(
+      (char *)GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
+  GPR_ASSERT(json != NULL);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  claims = grpc_jwt_claims_from_json(&exec_ctx, json, s);
+  GPR_ASSERT(claims != NULL);
+  GPR_ASSERT(grpc_jwt_claims_check(claims, "https://foo.com") ==
+             GRPC_JWT_VERIFIER_BAD_SUBJECT);
+  grpc_jwt_claims_destroy(&exec_ctx, claims);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static char *json_key_str(const char *last_part) {
@@ -294,18 +356,18 @@
                     "/robot/v1/metadata/x509/"
                     "777-abaslkan11hlb6nmim3bpspl31ud@developer."
                     "gserviceaccount.com") == 0);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
-static void on_verification_success(void *user_data,
+static void on_verification_success(grpc_exec_ctx *exec_ctx, void *user_data,
                                     grpc_jwt_verifier_status status,
                                     grpc_jwt_claims *claims) {
   GPR_ASSERT(status == GRPC_JWT_VERIFIER_OK);
   GPR_ASSERT(claims != NULL);
   GPR_ASSERT(user_data == (void *)expected_user_data);
   GPR_ASSERT(strcmp(grpc_jwt_claims_audience(claims), expected_audience) == 0);
-  grpc_jwt_claims_destroy(claims);
+  grpc_jwt_claims_destroy(exec_ctx, claims);
 }
 
 static void test_jwt_verifier_google_email_issuer_success(void) {
@@ -338,7 +400,7 @@
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0);
   GPR_ASSERT(strcmp(request->http.path, "/jwk/foo@bar.com") == 0);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -372,7 +434,7 @@
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
   GPR_ASSERT(strcmp(request->http.path, "/oauth2/v3/certs") == 0);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -387,7 +449,7 @@
   GPR_ASSERT(strcmp(request->http.path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0);
   grpc_httpcli_set_override(httpcli_get_jwk_set,
                             httpcli_post_should_not_be_called);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -413,7 +475,8 @@
   grpc_httpcli_set_override(NULL, NULL);
 }
 
-static void on_verification_key_retrieval_error(void *user_data,
+static void on_verification_key_retrieval_error(grpc_exec_ctx *exec_ctx,
+                                                void *user_data,
                                                 grpc_jwt_verifier_status status,
                                                 grpc_jwt_claims *claims) {
   GPR_ASSERT(status == GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR);
@@ -427,7 +490,7 @@
                                 grpc_httpcli_response *response) {
   *response = http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
-  grpc_exec_ctx_sched(exec_ctx, on_done, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, on_done, GRPC_ERROR_NONE);
   return 1;
 }
 
@@ -483,7 +546,11 @@
   uint8_t *sig_bytes;
   char *last_dot = strrchr(jwt, '.');
   GPR_ASSERT(last_dot != NULL);
-  sig = grpc_base64_decode(last_dot + 1, 1);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    sig = grpc_base64_decode(&exec_ctx, last_dot + 1, 1);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   GPR_ASSERT(!GRPC_SLICE_IS_EMPTY(sig));
   sig_bytes = GRPC_SLICE_START_PTR(sig);
   (*sig_bytes)++; /* Corrupt first byte. */
@@ -494,7 +561,8 @@
   grpc_slice_unref(sig);
 }
 
-static void on_verification_bad_signature(void *user_data,
+static void on_verification_bad_signature(grpc_exec_ctx *exec_ctx,
+                                          void *user_data,
                                           grpc_jwt_verifier_status status,
                                           grpc_jwt_claims *claims) {
   GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_SIGNATURE);
@@ -535,7 +603,7 @@
   return 1;
 }
 
-static void on_verification_bad_format(void *user_data,
+static void on_verification_bad_format(grpc_exec_ctx *exec_ctx, void *user_data,
                                        grpc_jwt_verifier_status status,
                                        grpc_jwt_claims *claims) {
   GPR_ASSERT(status == GRPC_JWT_VERIFIER_BAD_FORMAT);
@@ -563,10 +631,12 @@
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   grpc_init();
+  test_jwt_issuer_email_domain();
   test_claims_success();
   test_expired_claims_failure();
   test_invalid_claims_failure();
   test_bad_audience_claims_failure();
+  test_bad_subject_claims_failure();
   test_jwt_verifier_google_email_issuer_success();
   test_jwt_verifier_custom_email_issuer_success();
   test_jwt_verifier_url_issuer_success();
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index 44a2092..ff77af9 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -92,7 +92,8 @@
   request.pops = grpc_polling_entity_create_from_pollset(pollset);
   request.is_done = 0;
 
-  grpc_closure_init(&do_nothing_closure, do_nothing, NULL);
+  grpc_closure_init(&do_nothing_closure, do_nothing, NULL,
+                    grpc_schedule_on_exec_ctx);
 
   grpc_call_credentials_get_request_metadata(
       &exec_ctx, creds, &request.pops, null_ctx, on_oauth2_response, &request);
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index b5d9500..e1d6ff9 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -42,6 +42,7 @@
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/tsi/fake_transport_security.h"
 #include "test/core/util/test_config.h"
 
@@ -59,7 +60,7 @@
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("secure_endpoint_test");
   tcp = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, slice_size);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, tcp.client, g_pollset);
   grpc_endpoint_add_to_pollset(&exec_ctx, tcp.server, g_pollset);
 
@@ -158,7 +159,7 @@
   gpr_log(GPR_INFO, "Start test left over");
 
   grpc_slice_buffer_init(&incoming);
-  grpc_closure_init(&done_closure, inc_call_ctr, &n);
+  grpc_closure_init(&done_closure, inc_call_ctr, &n, grpc_schedule_on_exec_ctx);
   grpc_endpoint_read(&exec_ctx, f.client_ep, &incoming, &done_closure);
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_ASSERT(n == 1);
@@ -170,8 +171,8 @@
   grpc_endpoint_destroy(&exec_ctx, f.client_ep);
   grpc_endpoint_destroy(&exec_ctx, f.server_ep);
   grpc_exec_ctx_finish(&exec_ctx);
-  grpc_slice_unref(s);
-  grpc_slice_buffer_destroy(&incoming);
+  grpc_slice_unref_internal(&exec_ctx, s);
+  grpc_slice_buffer_destroy_internal(&exec_ctx, &incoming);
 
   clean_up();
 }
@@ -191,7 +192,8 @@
   grpc_pollset_init(g_pollset, &g_mu);
   grpc_endpoint_tests(configs[0], g_pollset, g_mu);
   test_leftover(configs[1], 1);
-  grpc_closure_init(&destroyed, destroy_pollset, g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, g_pollset,
+                    grpc_schedule_on_exec_ctx);
   grpc_pollset_shutdown(&exec_ctx, g_pollset, &destroyed);
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/security/ssl_server_fuzzer.c b/test/core/security/ssl_server_fuzzer.c
index 8673225..55e8f5e 100644
--- a/test/core/security/ssl_server_fuzzer.c
+++ b/test/core/security/ssl_server_fuzzer.c
@@ -79,7 +79,7 @@
       grpc_resource_quota_create("ssl_server_fuzzer");
   grpc_endpoint *mock_endpoint =
       grpc_mock_endpoint_create(discard_write, resource_quota);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
 
   grpc_mock_endpoint_put_read(
       &exec_ctx, mock_endpoint,
@@ -103,7 +103,7 @@
   // Create security connector
   grpc_server_security_connector *sc = NULL;
   grpc_security_status status =
-      grpc_server_credentials_create_security_connector(creds, &sc);
+      grpc_server_credentials_create_security_connector(&exec_ctx, creds, &sc);
   GPR_ASSERT(status == GRPC_SECURITY_OK);
   gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                                        gpr_time_from_seconds(1, GPR_TIMESPAN));
@@ -128,7 +128,7 @@
   GPR_ASSERT(state.done_callback_called);
 
   grpc_handshake_manager_destroy(&exec_ctx, handshake_mgr);
-  GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "test");
+  GRPC_SECURITY_CONNECTOR_UNREF(&exec_ctx, &sc->base, "test");
   grpc_server_credentials_release(creds);
   grpc_slice_unref(cert_slice);
   grpc_slice_unref(key_slice);
diff --git a/test/core/security/verify_jwt.c b/test/core/security/verify_jwt.c
index 043d29e..bbd4a67 100644
--- a/test/core/security/verify_jwt.c
+++ b/test/core/security/verify_jwt.c
@@ -59,7 +59,7 @@
   exit(1);
 }
 
-static void on_jwt_verification_done(void *user_data,
+static void on_jwt_verification_done(grpc_exec_ctx *exec_ctx, void *user_data,
                                      grpc_jwt_verifier_status status,
                                      grpc_jwt_claims *claims) {
   synchronizer *sync = user_data;
@@ -72,7 +72,7 @@
         grpc_json_dump_to_string((grpc_json *)grpc_jwt_claims_json(claims), 2);
     printf("Claims: \n\n%s\n", claims_str);
     gpr_free(claims_str);
-    grpc_jwt_claims_destroy(claims);
+    grpc_jwt_claims_destroy(exec_ctx, claims);
   } else {
     GPR_ASSERT(claims == NULL);
     fprintf(stderr, "Verification failed with error %s\n",
@@ -93,6 +93,7 @@
   char *aud = NULL;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
+  grpc_init();
   cl = gpr_cmdline_create("JWT verifier tool");
   gpr_cmdline_add_string(cl, "jwt", "JSON web token to verify", &jwt);
   gpr_cmdline_add_string(cl, "aud", "Audience for the JWT", &aud);
@@ -131,5 +132,6 @@
 
   grpc_jwt_verifier_destroy(verifier);
   gpr_cmdline_destroy(cl);
+  grpc_shutdown();
   return !sync.success;
 }
diff --git a/test/core/support/BUILD b/test/core/support/BUILD
new file mode 100644
index 0000000..dfe952e
--- /dev/null
+++ b/test/core/support/BUILD
@@ -0,0 +1,154 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+cc_test(
+    name = "alloc_test",
+    srcs = ["alloc_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "avl_test",
+    srcs = ["avl_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "backoff_test",
+    srcs = ["backoff_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "cmdline_test",
+    srcs = ["cmdline_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "cpu_test",
+    srcs = ["cpu_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "env_test",
+    srcs = ["env_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "histogram_test",
+    srcs = ["histogram_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "host_port_test",
+    srcs = ["host_port_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "log_test",
+    srcs = ["log_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "mpscq_test",
+    srcs = ["mpscq_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "murmur_hash_test",
+    srcs = ["murmur_hash_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "stack_lockfree_test",
+    srcs = ["stack_lockfree_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "string_test",
+    srcs = ["string_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "sync_test",
+    srcs = ["sync_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "thd_test",
+    srcs = ["thd_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "time_test",
+    srcs = ["time_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "tls_test",
+    srcs = ["tls_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
+
+cc_test(
+    name = "useful_test",
+    srcs = ["useful_test.c"],
+    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
+    copts = ['-std=c99']
+)
diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c
index 78b77fa..af232db 100644
--- a/test/core/support/string_test.c
+++ b/test/core/support/string_test.c
@@ -243,6 +243,8 @@
 static void test_leftpad() {
   char *padded;
 
+  LOG_TEST_NAME("test_leftpad");
+
   padded = gpr_leftpad("foo", ' ', 5);
   GPR_ASSERT(0 == strcmp("  foo", padded));
   gpr_free(padded);
@@ -273,12 +275,25 @@
 }
 
 static void test_stricmp(void) {
+  LOG_TEST_NAME("test_stricmp");
+
   GPR_ASSERT(0 == gpr_stricmp("hello", "hello"));
   GPR_ASSERT(0 == gpr_stricmp("HELLO", "hello"));
   GPR_ASSERT(gpr_stricmp("a", "b") < 0);
   GPR_ASSERT(gpr_stricmp("b", "a") > 0);
 }
 
+static void test_memrchr(void) {
+  LOG_TEST_NAME("test_memrchr");
+
+  GPR_ASSERT(NULL == gpr_memrchr(NULL, 'a', 0));
+  GPR_ASSERT(NULL == gpr_memrchr("", 'a', 0));
+  GPR_ASSERT(NULL == gpr_memrchr("hello", 'b', 5));
+  GPR_ASSERT(0 == strcmp((const char *)gpr_memrchr("hello", 'h', 5), "hello"));
+  GPR_ASSERT(0 == strcmp((const char *)gpr_memrchr("hello", 'o', 5), "o"));
+  GPR_ASSERT(0 == strcmp((const char *)gpr_memrchr("hello", 'l', 5), "lo"));
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_strdup();
@@ -291,5 +306,6 @@
   test_int64toa();
   test_leftpad();
   test_stricmp();
+  test_memrchr();
   return 0;
 }
diff --git a/test/core/surface/byte_buffer_reader_test.c b/test/core/surface/byte_buffer_reader_test.c
index d8d7a52..2f1f72f 100644
--- a/test/core/surface/byte_buffer_reader_test.c
+++ b/test/core/surface/byte_buffer_reader_test.c
@@ -40,9 +40,10 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include "test/core/util/test_config.h"
 
 #include "src/core/lib/compression/message_compress.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "test/core/util/test_config.h"
 
 #include <string.h>
 
@@ -145,7 +146,12 @@
   input_slice = grpc_slice_malloc(input_size);
   memset(GRPC_SLICE_START_PTR(input_slice), 'a', input_size);
   grpc_slice_buffer_add(&sliceb_in, input_slice); /* takes ownership */
-  GPR_ASSERT(grpc_msg_compress(algorithm, &sliceb_in, &sliceb_out));
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    GPR_ASSERT(
+        grpc_msg_compress(&exec_ctx, algorithm, &sliceb_in, &sliceb_out));
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 
   buffer = grpc_raw_compressed_byte_buffer_create(sliceb_out.slices,
                                                   sliceb_out.count, algorithm);
diff --git a/test/core/surface/channel_create_test.c b/test/core/surface/channel_create_test.c
index ad7970a..654e532 100644
--- a/test/core/surface/channel_create_test.c
+++ b/test/core/surface/channel_create_test.c
@@ -31,9 +31,14 @@
  *
  */
 
+#include <string.h>
+
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
+
 #include "src/core/ext/client_channel/resolver_registry.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/surface/channel.h"
 #include "test/core/util/test_config.h"
 
 void test_unknown_scheme_target(void) {
@@ -44,6 +49,13 @@
 
   chan = grpc_insecure_channel_create("blah://blah", NULL, NULL);
   GPR_ASSERT(chan != NULL);
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_channel_element *elem =
+      grpc_channel_stack_element(grpc_channel_get_channel_stack(chan), 0);
+  GPR_ASSERT(0 == strcmp(elem->filter->name, "lame-client"));
+  grpc_exec_ctx_finish(&exec_ctx);
+
   grpc_channel_destroy(chan);
 }
 
diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c
index 93a4794..8ebe8d0 100644
--- a/test/core/surface/concurrent_connectivity_test.c
+++ b/test/core/surface/concurrent_connectivity_test.c
@@ -229,9 +229,9 @@
   gpr_atm_rel_store(&args.stop, 1);
   gpr_thd_join(server);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_pollset_shutdown(
-      &exec_ctx, args.pollset,
-      grpc_closure_create(done_pollset_shutdown, args.pollset));
+  grpc_pollset_shutdown(&exec_ctx, args.pollset,
+                        grpc_closure_create(done_pollset_shutdown, args.pollset,
+                                            grpc_schedule_on_exec_ctx));
   grpc_exec_ctx_finish(&exec_ctx);
 
   grpc_shutdown();
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
index 6afcefc..b6db6a6 100644
--- a/test/core/surface/lame_client_test.c
+++ b/test/core/surface/lame_client_test.c
@@ -62,7 +62,8 @@
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
-  grpc_closure_init(&transport_op_cb, verify_connectivity, &state);
+  grpc_closure_init(&transport_op_cb, verify_connectivity, &state,
+                    grpc_schedule_on_exec_ctx);
 
   op = grpc_make_transport_op(NULL);
   op->on_connectivity_state_change = &transport_op_cb;
@@ -71,7 +72,8 @@
   elem->filter->start_transport_op(&exec_ctx, elem, op);
   grpc_exec_ctx_finish(&exec_ctx);
 
-  grpc_closure_init(&transport_op_cb, do_nothing, NULL);
+  grpc_closure_init(&transport_op_cb, do_nothing, NULL,
+                    grpc_schedule_on_exec_ctx);
   op = grpc_make_transport_op(&transport_op_cb);
   elem->filter->start_transport_op(&exec_ctx, elem, op);
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index d4cfa25..6104953 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -42,6 +42,7 @@
 #include <grpc/impl/codegen/byte_buffer_reader.h>
 #include <grpc/impl/codegen/compression_types.h>
 #include <grpc/impl/codegen/connectivity_state.h>
+#include <grpc/impl/codegen/exec_ctx_fwd.h>
 #include <grpc/impl/codegen/gpr_types.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/impl/codegen/port_platform.h>
diff --git a/test/core/surface/secure_channel_create_test.c b/test/core/surface/secure_channel_create_test.c
index 444ebdc..ab4067d 100644
--- a/test/core/surface/secure_channel_create_test.c
+++ b/test/core/surface/secure_channel_create_test.c
@@ -51,7 +51,9 @@
   creds = grpc_fake_transport_security_credentials_create();
   chan = grpc_secure_channel_create(creds, "blah://blah", NULL, NULL);
   GPR_ASSERT(chan == NULL);
-  grpc_channel_credentials_unref(creds);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_channel_credentials_unref(&exec_ctx, creds);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 void test_security_connector_already_in_arg(void) {
diff --git a/test/core/surface/sequential_connectivity_test.c b/test/core/surface/sequential_connectivity_test.c
index fe87f11..3292718 100644
--- a/test/core/surface/sequential_connectivity_test.c
+++ b/test/core/surface/sequential_connectivity_test.c
@@ -39,6 +39,7 @@
 #include <grpc/support/thd.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
@@ -162,7 +163,11 @@
       grpc_channel_args_copy_and_add(NULL, &ssl_name_override, 1);
   grpc_channel *channel =
       grpc_secure_channel_create(ssl_creds, addr, new_client_args, NULL);
-  grpc_channel_args_destroy(new_client_args);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, new_client_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
   grpc_channel_credentials_release(ssl_creds);
   return channel;
 }
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/core/transport/chttp2/BUILD
old mode 100755
new mode 100644
similarity index 85%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/core/transport/chttp2/BUILD
index 7438713..5dd2051
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/core/transport/chttp2/BUILD
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cd $(dirname $0)/../..
+grpc_fuzzer(
+  name = "hpack_parser_fuzzer",
+  srcs = ["hpack_parser_fuzzer_test.c"],
+  deps = ["//:grpc", "//test/core/util:grpc_test_util"],
+  corpus = "hpack_parser_corpus"
+)
 
-make grpc_csharp_ext
-
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
diff --git a/test/core/transport/chttp2/bin_decoder_test.c b/test/core/transport/chttp2/bin_decoder_test.c
index 7ddc302..221112a 100644
--- a/test/core/transport/chttp2/bin_decoder_test.c
+++ b/test/core/transport/chttp2/bin_decoder_test.c
@@ -38,13 +38,14 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
 static int all_ok = 1;
 
-static void expect_slice_eq(grpc_slice expected, grpc_slice slice, char *debug,
-                            int line) {
+static void expect_slice_eq(grpc_exec_ctx *exec_ctx, grpc_slice expected,
+                            grpc_slice slice, char *debug, int line) {
   if (0 != grpc_slice_cmp(slice, expected)) {
     char *hs = grpc_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
     char *he = grpc_dump_slice(expected, GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -54,92 +55,104 @@
     gpr_free(he);
     all_ok = 0;
   }
-  grpc_slice_unref(expected);
-  grpc_slice_unref(slice);
+  grpc_slice_unref_internal(exec_ctx, expected);
+  grpc_slice_unref_internal(exec_ctx, slice);
 }
 
-static grpc_slice base64_encode(const char *s) {
+static grpc_slice base64_encode(grpc_exec_ctx *exec_ctx, const char *s) {
   grpc_slice ss = grpc_slice_from_copied_string(s);
   grpc_slice out = grpc_chttp2_base64_encode(ss);
-  grpc_slice_unref(ss);
+  grpc_slice_unref_internal(exec_ctx, ss);
   return out;
 }
 
-static grpc_slice base64_decode(const char *s) {
+static grpc_slice base64_decode(grpc_exec_ctx *exec_ctx, const char *s) {
   grpc_slice ss = grpc_slice_from_copied_string(s);
-  grpc_slice out = grpc_chttp2_base64_decode(ss);
-  grpc_slice_unref(ss);
+  grpc_slice out = grpc_chttp2_base64_decode(exec_ctx, ss);
+  grpc_slice_unref_internal(exec_ctx, ss);
   return out;
 }
 
-static grpc_slice base64_decode_with_length(const char *s,
+static grpc_slice base64_decode_with_length(grpc_exec_ctx *exec_ctx,
+                                            const char *s,
                                             size_t output_length) {
   grpc_slice ss = grpc_slice_from_copied_string(s);
-  grpc_slice out = grpc_chttp2_base64_decode_with_length(ss, output_length);
-  grpc_slice_unref(ss);
+  grpc_slice out =
+      grpc_chttp2_base64_decode_with_length(exec_ctx, ss, output_length);
+  grpc_slice_unref_internal(exec_ctx, ss);
   return out;
 }
 
-#define EXPECT_SLICE_EQ(expected, slice)                                    \
-  expect_slice_eq(                                                          \
-      grpc_slice_from_copied_buffer(expected, sizeof(expected) - 1), slice, \
-      #slice, __LINE__);
+#define EXPECT_SLICE_EQ(exec_ctx, expected, slice)                             \
+  expect_slice_eq(                                                             \
+      exec_ctx, grpc_slice_from_copied_buffer(expected, sizeof(expected) - 1), \
+      slice, #slice, __LINE__);
 
-#define ENCODE_AND_DECODE(s) \
-  EXPECT_SLICE_EQ(           \
-      s, grpc_chttp2_base64_decode_with_length(base64_encode(s), strlen(s)));
+#define ENCODE_AND_DECODE(exec_ctx, s)                   \
+  EXPECT_SLICE_EQ(exec_ctx, s,                           \
+                  grpc_chttp2_base64_decode_with_length( \
+                      exec_ctx, base64_encode(exec_ctx, s), strlen(s)));
 
 int main(int argc, char **argv) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
   /* ENCODE_AND_DECODE tests grpc_chttp2_base64_decode_with_length(), which
      takes encoded base64 strings without pad chars, but output length is
      required. */
   /* Base64 test vectors from RFC 4648 */
-  ENCODE_AND_DECODE("");
-  ENCODE_AND_DECODE("f");
-  ENCODE_AND_DECODE("foo");
-  ENCODE_AND_DECODE("fo");
-  ENCODE_AND_DECODE("foob");
-  ENCODE_AND_DECODE("fooba");
-  ENCODE_AND_DECODE("foobar");
+  ENCODE_AND_DECODE(&exec_ctx, "");
+  ENCODE_AND_DECODE(&exec_ctx, "f");
+  ENCODE_AND_DECODE(&exec_ctx, "foo");
+  ENCODE_AND_DECODE(&exec_ctx, "fo");
+  ENCODE_AND_DECODE(&exec_ctx, "foob");
+  ENCODE_AND_DECODE(&exec_ctx, "fooba");
+  ENCODE_AND_DECODE(&exec_ctx, "foobar");
 
-  ENCODE_AND_DECODE("\xc0\xc1\xc2\xc3\xc4\xc5");
+  ENCODE_AND_DECODE(&exec_ctx, "\xc0\xc1\xc2\xc3\xc4\xc5");
 
   /* Base64 test vectors from RFC 4648, with pad chars */
   /* BASE64("") = "" */
-  EXPECT_SLICE_EQ("", base64_decode(""));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode(&exec_ctx, ""));
   /* BASE64("f") = "Zg==" */
-  EXPECT_SLICE_EQ("f", base64_decode("Zg=="));
+  EXPECT_SLICE_EQ(&exec_ctx, "f", base64_decode(&exec_ctx, "Zg=="));
   /* BASE64("fo") = "Zm8=" */
-  EXPECT_SLICE_EQ("fo", base64_decode("Zm8="));
+  EXPECT_SLICE_EQ(&exec_ctx, "fo", base64_decode(&exec_ctx, "Zm8="));
   /* BASE64("foo") = "Zm9v" */
-  EXPECT_SLICE_EQ("foo", base64_decode("Zm9v"));
+  EXPECT_SLICE_EQ(&exec_ctx, "foo", base64_decode(&exec_ctx, "Zm9v"));
   /* BASE64("foob") = "Zm9vYg==" */
-  EXPECT_SLICE_EQ("foob", base64_decode("Zm9vYg=="));
+  EXPECT_SLICE_EQ(&exec_ctx, "foob", base64_decode(&exec_ctx, "Zm9vYg=="));
   /* BASE64("fooba") = "Zm9vYmE=" */
-  EXPECT_SLICE_EQ("fooba", base64_decode("Zm9vYmE="));
+  EXPECT_SLICE_EQ(&exec_ctx, "fooba", base64_decode(&exec_ctx, "Zm9vYmE="));
   /* BASE64("foobar") = "Zm9vYmFy" */
-  EXPECT_SLICE_EQ("foobar", base64_decode("Zm9vYmFy"));
+  EXPECT_SLICE_EQ(&exec_ctx, "foobar", base64_decode(&exec_ctx, "Zm9vYmFy"));
 
-  EXPECT_SLICE_EQ("\xc0\xc1\xc2\xc3\xc4\xc5", base64_decode("wMHCw8TF"));
+  EXPECT_SLICE_EQ(&exec_ctx, "\xc0\xc1\xc2\xc3\xc4\xc5",
+                  base64_decode(&exec_ctx, "wMHCw8TF"));
 
   // Test illegal input length in grpc_chttp2_base64_decode
-  EXPECT_SLICE_EQ("", base64_decode("a"));
-  EXPECT_SLICE_EQ("", base64_decode("ab"));
-  EXPECT_SLICE_EQ("", base64_decode("abc"));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode(&exec_ctx, "a"));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode(&exec_ctx, "ab"));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode(&exec_ctx, "abc"));
 
   // Test illegal charactors in grpc_chttp2_base64_decode
-  EXPECT_SLICE_EQ("", base64_decode("Zm:v"));
-  EXPECT_SLICE_EQ("", base64_decode("Zm=v"));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode(&exec_ctx, "Zm:v"));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode(&exec_ctx, "Zm=v"));
 
   // Test output_length longer than max possible output length in
   // grpc_chttp2_base64_decode_with_length
-  EXPECT_SLICE_EQ("", base64_decode_with_length("Zg", 2));
-  EXPECT_SLICE_EQ("", base64_decode_with_length("Zm8", 3));
-  EXPECT_SLICE_EQ("", base64_decode_with_length("Zm9v", 4));
+  EXPECT_SLICE_EQ(&exec_ctx, "", base64_decode_with_length(&exec_ctx, "Zg", 2));
+  EXPECT_SLICE_EQ(&exec_ctx, "",
+                  base64_decode_with_length(&exec_ctx, "Zm8", 3));
+  EXPECT_SLICE_EQ(&exec_ctx, "",
+                  base64_decode_with_length(&exec_ctx, "Zm9v", 4));
 
   // Test illegal charactors in grpc_chttp2_base64_decode_with_length
-  EXPECT_SLICE_EQ("", base64_decode_with_length("Zm:v", 3));
-  EXPECT_SLICE_EQ("", base64_decode_with_length("Zm=v", 3));
+  EXPECT_SLICE_EQ(&exec_ctx, "",
+                  base64_decode_with_length(&exec_ctx, "Zm:v", 3));
+  EXPECT_SLICE_EQ(&exec_ctx, "",
+                  base64_decode_with_length(&exec_ctx, "Zm=v", 3));
+
+  grpc_exec_ctx_finish(&exec_ctx);
 
   return all_ok ? 0 : 1;
 }
diff --git a/test/core/transport/chttp2/hpack_encoder_test.c b/test/core/transport/chttp2/hpack_encoder_test.c
index 91421e1..1fd2540 100644
--- a/test/core/transport/chttp2/hpack_encoder_test.c
+++ b/test/core/transport/chttp2/hpack_encoder_test.c
@@ -41,6 +41,7 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/metadata.h"
@@ -59,8 +60,9 @@
 
 /* verify that the output generated by encoding the stream matches the
    hexstring passed in */
-static void verify(size_t window_available, int eof, size_t expect_window_used,
-                   const char *expected, size_t nheaders, ...) {
+static void verify(grpc_exec_ctx *exec_ctx, size_t window_available, int eof,
+                   size_t expect_window_used, const char *expected,
+                   size_t nheaders, ...) {
   grpc_slice_buffer output;
   grpc_slice merged;
   grpc_slice expect = parse_hexstring(expected);
@@ -79,7 +81,7 @@
       e[i - 1].next = &e[i];
       e[i].prev = &e[i - 1];
     }
-    e[i].md = grpc_mdelem_from_strings(key, value);
+    e[i].md = grpc_mdelem_from_strings(exec_ctx, key, value);
   }
   e[0].prev = NULL;
   e[nheaders - 1].next = NULL;
@@ -98,11 +100,11 @@
 
   grpc_transport_one_way_stats stats;
   memset(&stats, 0, sizeof(stats));
-  grpc_chttp2_encode_header(&g_compressor, 0xdeadbeef, &b, eof, 16384, &stats,
-                            &output);
+  grpc_chttp2_encode_header(exec_ctx, &g_compressor, 0xdeadbeef, &b, eof, 16384,
+                            &stats, &output);
   merged = grpc_slice_merge(output.slices, output.count);
-  grpc_slice_buffer_destroy(&output);
-  grpc_metadata_batch_destroy(&b);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &output);
+  grpc_metadata_batch_destroy(exec_ctx, &b);
 
   if (0 != grpc_slice_cmp(merged, expect)) {
     char *expect_str = grpc_dump_slice(expect, GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -115,31 +117,32 @@
     g_failure = 1;
   }
 
-  grpc_slice_unref(merged);
-  grpc_slice_unref(expect);
+  grpc_slice_unref_internal(exec_ctx, merged);
+  grpc_slice_unref_internal(exec_ctx, expect);
 }
 
-static void test_basic_headers(void) {
+static void test_basic_headers(grpc_exec_ctx *exec_ctx) {
   int i;
 
-  verify(0, 0, 0, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
-  verify(0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a");
-  verify(0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a");
-  verify(0, 0, 0, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a", "b",
+  verify(exec_ctx, 0, 0, 0, "000005 0104 deadbeef 40 0161 0161", 1, "a", "a");
+  verify(exec_ctx, 0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a");
+  verify(exec_ctx, 0, 0, 0, "000001 0104 deadbeef be", 1, "a", "a");
+  verify(exec_ctx, 0, 0, 0, "000006 0104 deadbeef be 40 0162 0163", 2, "a", "a",
+         "b", "c");
+  verify(exec_ctx, 0, 0, 0, "000002 0104 deadbeef bf be", 2, "a", "a", "b",
          "c");
-  verify(0, 0, 0, "000002 0104 deadbeef bf be", 2, "a", "a", "b", "c");
-  verify(0, 0, 0, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d");
+  verify(exec_ctx, 0, 0, 0, "000004 0104 deadbeef 7f 00 0164", 1, "a", "d");
 
   /* flush out what's there to make a few values look very popular */
   for (i = 0; i < 350; i++) {
-    verify(0, 0, 0, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b", "c", "a",
-           "d");
+    verify(exec_ctx, 0, 0, 0, "000003 0104 deadbeef c0 bf be", 3, "a", "a", "b",
+           "c", "a", "d");
   }
 
-  verify(0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a", "k",
-         "v");
+  verify(exec_ctx, 0, 0, 0, "000006 0104 deadbeef c0 00 016b 0176", 2, "a", "a",
+         "k", "v");
   /* this could be 000004 0104 deadbeef 0f 30 0176 also */
-  verify(0, 0, 0, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
+  verify(exec_ctx, 0, 0, 0, "000004 0104 deadbeef 0f 2f 0176", 1, "a", "v");
 }
 
 static void encode_int_to_str(int i, char *p) {
@@ -150,7 +153,7 @@
   p[2] = 0;
 }
 
-static void test_decode_table_overflow(void) {
+static void test_decode_table_overflow(grpc_exec_ctx *exec_ctx) {
   int i;
   char key[3], value[3];
   char *expect;
@@ -173,22 +176,24 @@
     }
 
     if (i > 0) {
-      verify(0, 0, 0, expect, 2, "aa", "ba", key, value);
+      verify(exec_ctx, 0, 0, 0, expect, 2, "aa", "ba", key, value);
     } else {
-      verify(0, 0, 0, expect, 1, key, value);
+      verify(exec_ctx, 0, 0, 0, expect, 1, key, value);
     }
     gpr_free(expect);
   }
 
   /* if the above passes, then we must have just knocked this pair out of the
      decoder stack, and so we'll be forced to re-encode it */
-  verify(0, 0, 0, "000007 0104 deadbeef 40 026161 026261", 1, "aa", "ba");
+  verify(exec_ctx, 0, 0, 0, "000007 0104 deadbeef 40 026161 026261", 1, "aa",
+         "ba");
 }
 
-static void verify_table_size_change_match_elem_size(const char *key,
+static void verify_table_size_change_match_elem_size(grpc_exec_ctx *exec_ctx,
+                                                     const char *key,
                                                      const char *value) {
   grpc_slice_buffer output;
-  grpc_mdelem *elem = grpc_mdelem_from_strings(key, value);
+  grpc_mdelem *elem = grpc_mdelem_from_strings(exec_ctx, key, value);
   size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
   size_t initial_table_size = g_compressor.table_size;
   grpc_linked_mdelem *e = gpr_malloc(sizeof(*e));
@@ -203,25 +208,27 @@
 
   grpc_transport_one_way_stats stats;
   memset(&stats, 0, sizeof(stats));
-  grpc_chttp2_encode_header(&g_compressor, 0xdeadbeef, &b, 0, 16384, &stats,
-                            &output);
-  grpc_slice_buffer_destroy(&output);
-  grpc_metadata_batch_destroy(&b);
+  grpc_chttp2_encode_header(exec_ctx, &g_compressor, 0xdeadbeef, &b, 0, 16384,
+                            &stats, &output);
+  grpc_slice_buffer_destroy_internal(exec_ctx, &output);
+  grpc_metadata_batch_destroy(exec_ctx, &b);
 
   GPR_ASSERT(g_compressor.table_size == elem_size + initial_table_size);
   gpr_free(e);
 }
 
-static void test_encode_header_size(void) {
-  verify_table_size_change_match_elem_size("hello", "world");
-  verify_table_size_change_match_elem_size("hello-bin", "world");
+static void test_encode_header_size(grpc_exec_ctx *exec_ctx) {
+  verify_table_size_change_match_elem_size(exec_ctx, "hello", "world");
+  verify_table_size_change_match_elem_size(exec_ctx, "hello-bin", "world");
 }
 
-static void run_test(void (*test)(), const char *name) {
+static void run_test(void (*test)(grpc_exec_ctx *exec_ctx), const char *name) {
   gpr_log(GPR_INFO, "RUN TEST: %s", name);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_chttp2_hpack_compressor_init(&g_compressor);
-  test();
-  grpc_chttp2_hpack_compressor_destroy(&g_compressor);
+  test(&exec_ctx);
+  grpc_chttp2_hpack_compressor_destroy(&exec_ctx, &g_compressor);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/transport/chttp2/hpack_parser_fuzzer_test.c b/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
index 95acbf1..4e00f49 100644
--- a/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
+++ b/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
@@ -44,7 +44,7 @@
 bool leak_check = true;
 
 static void onhdr(grpc_exec_ctx *exec_ctx, void *ud, grpc_mdelem *md) {
-  GRPC_MDELEM_UNREF(md);
+  GRPC_MDELEM_UNREF(exec_ctx, md);
 }
 static void dont_log(gpr_log_func_args *args) {}
 
@@ -53,13 +53,13 @@
   if (squelch) gpr_set_log_function(dont_log);
   grpc_init();
   grpc_chttp2_hpack_parser parser;
-  grpc_chttp2_hpack_parser_init(&parser);
-  parser.on_header = onhdr;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_chttp2_hpack_parser_init(&exec_ctx, &parser);
+  parser.on_header = onhdr;
   GRPC_ERROR_UNREF(
       grpc_chttp2_hpack_parser_parse(&exec_ctx, &parser, data, data + size));
+  grpc_chttp2_hpack_parser_destroy(&exec_ctx, &parser);
   grpc_exec_ctx_finish(&exec_ctx);
-  grpc_chttp2_hpack_parser_destroy(&parser);
   grpc_shutdown();
   return 0;
 }
diff --git a/test/core/transport/chttp2/hpack_parser_test.c b/test/core/transport/chttp2/hpack_parser_test.c
index e2813df..8f48849 100644
--- a/test/core/transport/chttp2/hpack_parser_test.c
+++ b/test/core/transport/chttp2/hpack_parser_test.c
@@ -54,7 +54,7 @@
   GPR_ASSERT(evalue);
   GPR_ASSERT(grpc_slice_str_cmp(md->key->slice, ekey) == 0);
   GPR_ASSERT(grpc_slice_str_cmp(md->value->slice, evalue) == 0);
-  GRPC_MDELEM_UNREF(md);
+  GRPC_MDELEM_UNREF(exec_ctx, md);
 }
 
 static void test_vector(grpc_chttp2_hpack_parser *parser,
@@ -94,8 +94,9 @@
 
 static void test_vectors(grpc_slice_split_mode mode) {
   grpc_chttp2_hpack_parser parser;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
-  grpc_chttp2_hpack_parser_init(&parser);
+  grpc_chttp2_hpack_parser_init(&exec_ctx, &parser);
   /* D.2.1 */
   test_vector(&parser, mode,
               "400a 6375 7374 6f6d 2d6b 6579 0d63 7573"
@@ -111,9 +112,9 @@
               "password", "secret", NULL);
   /* D.2.4 */
   test_vector(&parser, mode, "82", ":method", "GET", NULL);
-  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_chttp2_hpack_parser_destroy(&exec_ctx, &parser);
 
-  grpc_chttp2_hpack_parser_init(&parser);
+  grpc_chttp2_hpack_parser_init(&exec_ctx, &parser);
   /* D.3.1 */
   test_vector(&parser, mode,
               "8286 8441 0f77 7777 2e65 7861 6d70 6c65"
@@ -131,9 +132,9 @@
               ":method", "GET", ":scheme", "https", ":path", "/index.html",
               ":authority", "www.example.com", "custom-key", "custom-value",
               NULL);
-  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_chttp2_hpack_parser_destroy(&exec_ctx, &parser);
 
-  grpc_chttp2_hpack_parser_init(&parser);
+  grpc_chttp2_hpack_parser_init(&exec_ctx, &parser);
   /* D.4.1 */
   test_vector(&parser, mode,
               "8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4"
@@ -151,11 +152,11 @@
               ":method", "GET", ":scheme", "https", ":path", "/index.html",
               ":authority", "www.example.com", "custom-key", "custom-value",
               NULL);
-  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_chttp2_hpack_parser_destroy(&exec_ctx, &parser);
 
-  grpc_chttp2_hpack_parser_init(&parser);
-  grpc_chttp2_hptbl_set_max_bytes(&parser.table, 256);
-  grpc_chttp2_hptbl_set_current_table_size(&parser.table, 256);
+  grpc_chttp2_hpack_parser_init(&exec_ctx, &parser);
+  grpc_chttp2_hptbl_set_max_bytes(&exec_ctx, &parser.table, 256);
+  grpc_chttp2_hptbl_set_current_table_size(&exec_ctx, &parser.table, 256);
   /* D.5.1 */
   test_vector(&parser, mode,
               "4803 3330 3258 0770 7269 7661 7465 611d"
@@ -185,11 +186,11 @@
               "https://www.example.com", "content-encoding", "gzip",
               "set-cookie",
               "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", NULL);
-  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_chttp2_hpack_parser_destroy(&exec_ctx, &parser);
 
-  grpc_chttp2_hpack_parser_init(&parser);
-  grpc_chttp2_hptbl_set_max_bytes(&parser.table, 256);
-  grpc_chttp2_hptbl_set_current_table_size(&parser.table, 256);
+  grpc_chttp2_hpack_parser_init(&exec_ctx, &parser);
+  grpc_chttp2_hptbl_set_max_bytes(&exec_ctx, &parser.table, 256);
+  grpc_chttp2_hptbl_set_current_table_size(&exec_ctx, &parser.table, 256);
   /* D.6.1 */
   test_vector(&parser, mode,
               "4882 6402 5885 aec3 771a 4b61 96d0 7abe"
@@ -216,7 +217,9 @@
               "https://www.example.com", "content-encoding", "gzip",
               "set-cookie",
               "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1", NULL);
-  grpc_chttp2_hpack_parser_destroy(&parser);
+  grpc_chttp2_hpack_parser_destroy(&exec_ctx, &parser);
+
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c
index 1a7e244..ef2ad66 100644
--- a/test/core/transport/chttp2/hpack_table_test.c
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -59,9 +59,10 @@
 }
 
 static void test_static_lookup(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_chttp2_hptbl tbl;
 
-  grpc_chttp2_hptbl_init(&tbl);
+  grpc_chttp2_hptbl_init(&exec_ctx, &tbl);
 
   LOG_TEST("test_static_lookup");
   assert_index(&tbl, 1, ":authority", "");
@@ -126,7 +127,8 @@
   assert_index(&tbl, 60, "via", "");
   assert_index(&tbl, 61, "www-authenticate", "");
 
-  grpc_chttp2_hptbl_destroy(&tbl);
+  grpc_chttp2_hptbl_destroy(&exec_ctx, &tbl);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_many_additions(void) {
@@ -137,15 +139,16 @@
 
   LOG_TEST("test_many_additions");
 
-  grpc_chttp2_hptbl_init(&tbl);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_chttp2_hptbl_init(&exec_ctx, &tbl);
 
   for (i = 0; i < 100000; i++) {
     grpc_mdelem *elem;
     gpr_asprintf(&key, "K:%d", i);
     gpr_asprintf(&value, "VALUE:%d", i);
-    elem = grpc_mdelem_from_strings(key, value);
-    GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem) == GRPC_ERROR_NONE);
-    GRPC_MDELEM_UNREF(elem);
+    elem = grpc_mdelem_from_strings(&exec_ctx, key, value);
+    GPR_ASSERT(grpc_chttp2_hptbl_add(&exec_ctx, &tbl, elem) == GRPC_ERROR_NONE);
+    GRPC_MDELEM_UNREF(&exec_ctx, elem);
     assert_index(&tbl, 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY, key, value);
     gpr_free(key);
     gpr_free(value);
@@ -158,19 +161,23 @@
     }
   }
 
-  grpc_chttp2_hptbl_destroy(&tbl);
+  grpc_chttp2_hptbl_destroy(&exec_ctx, &tbl);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static grpc_chttp2_hptbl_find_result find_simple(grpc_chttp2_hptbl *tbl,
                                                  const char *key,
                                                  const char *value) {
-  grpc_mdelem *md = grpc_mdelem_from_strings(key, value);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_mdelem *md = grpc_mdelem_from_strings(&exec_ctx, key, value);
   grpc_chttp2_hptbl_find_result r = grpc_chttp2_hptbl_find(tbl, md);
-  GRPC_MDELEM_UNREF(md);
+  GRPC_MDELEM_UNREF(&exec_ctx, md);
+  grpc_exec_ctx_finish(&exec_ctx);
   return r;
 }
 
 static void test_find(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_chttp2_hptbl tbl;
   uint32_t i;
   char buffer[32];
@@ -179,16 +186,16 @@
 
   LOG_TEST("test_find");
 
-  grpc_chttp2_hptbl_init(&tbl);
-  elem = grpc_mdelem_from_strings("abc", "xyz");
-  GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem) == GRPC_ERROR_NONE);
-  GRPC_MDELEM_UNREF(elem);
-  elem = grpc_mdelem_from_strings("abc", "123");
-  GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem) == GRPC_ERROR_NONE);
-  GRPC_MDELEM_UNREF(elem);
-  elem = grpc_mdelem_from_strings("x", "1");
-  GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem) == GRPC_ERROR_NONE);
-  GRPC_MDELEM_UNREF(elem);
+  grpc_chttp2_hptbl_init(&exec_ctx, &tbl);
+  elem = grpc_mdelem_from_strings(&exec_ctx, "abc", "xyz");
+  GPR_ASSERT(grpc_chttp2_hptbl_add(&exec_ctx, &tbl, elem) == GRPC_ERROR_NONE);
+  GRPC_MDELEM_UNREF(&exec_ctx, elem);
+  elem = grpc_mdelem_from_strings(&exec_ctx, "abc", "123");
+  GPR_ASSERT(grpc_chttp2_hptbl_add(&exec_ctx, &tbl, elem) == GRPC_ERROR_NONE);
+  GRPC_MDELEM_UNREF(&exec_ctx, elem);
+  elem = grpc_mdelem_from_strings(&exec_ctx, "x", "1");
+  GPR_ASSERT(grpc_chttp2_hptbl_add(&exec_ctx, &tbl, elem) == GRPC_ERROR_NONE);
+  GRPC_MDELEM_UNREF(&exec_ctx, elem);
 
   r = find_simple(&tbl, "abc", "123");
   GPR_ASSERT(r.index == 2 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
@@ -237,9 +244,9 @@
   /* overflow the string buffer, check find still works */
   for (i = 0; i < 10000; i++) {
     int64_ttoa(i, buffer);
-    elem = grpc_mdelem_from_strings("test", buffer);
-    GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem) == GRPC_ERROR_NONE);
-    GRPC_MDELEM_UNREF(elem);
+    elem = grpc_mdelem_from_strings(&exec_ctx, "test", buffer);
+    GPR_ASSERT(grpc_chttp2_hptbl_add(&exec_ctx, &tbl, elem) == GRPC_ERROR_NONE);
+    GRPC_MDELEM_UNREF(&exec_ctx, elem);
   }
 
   r = find_simple(&tbl, "abc", "123");
@@ -267,7 +274,8 @@
   GPR_ASSERT(r.index != 0);
   GPR_ASSERT(r.has_value == 0);
 
-  grpc_chttp2_hptbl_destroy(&tbl);
+  grpc_chttp2_hptbl_destroy(&exec_ctx, &tbl);
+  grpc_exec_ctx_finish(&exec_ctx);
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/transport/connectivity_state_test.c b/test/core/transport/connectivity_state_test.c
index 1050059..3520ef0 100644
--- a/test/core/transport/connectivity_state_test.c
+++ b/test/core/transport/connectivity_state_test.c
@@ -86,7 +86,8 @@
 
 static void test_subscribe_then_unsubscribe(void) {
   grpc_connectivity_state_tracker tracker;
-  grpc_closure *closure = grpc_closure_create(must_fail, THE_ARG);
+  grpc_closure *closure =
+      grpc_closure_create(must_fail, THE_ARG, grpc_schedule_on_exec_ctx);
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   gpr_log(GPR_DEBUG, "test_subscribe_then_unsubscribe");
@@ -109,7 +110,8 @@
 
 static void test_subscribe_then_destroy(void) {
   grpc_connectivity_state_tracker tracker;
-  grpc_closure *closure = grpc_closure_create(must_succeed, THE_ARG);
+  grpc_closure *closure =
+      grpc_closure_create(must_succeed, THE_ARG, grpc_schedule_on_exec_ctx);
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   gpr_log(GPR_DEBUG, "test_subscribe_then_destroy");
@@ -128,7 +130,8 @@
 
 static void test_subscribe_with_failure_then_destroy(void) {
   grpc_connectivity_state_tracker tracker;
-  grpc_closure *closure = grpc_closure_create(must_fail, THE_ARG);
+  grpc_closure *closure =
+      grpc_closure_create(must_fail, THE_ARG, grpc_schedule_on_exec_ctx);
   grpc_connectivity_state state = GRPC_CHANNEL_SHUTDOWN;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   gpr_log(GPR_DEBUG, "test_subscribe_with_failure_then_destroy");
diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c
index 5c89d85..3625043 100644
--- a/test/core/transport/metadata_test.c
+++ b/test/core/transport/metadata_test.c
@@ -42,6 +42,7 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
+#include "src/core/lib/slice/slice_internal.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/static_metadata.h"
 #include "test/core/util/test_config.h"
@@ -63,6 +64,7 @@
   LOG_TEST("test_create_string");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   s1 = grpc_mdstr_from_string("hello");
   s2 = grpc_mdstr_from_string("hello");
   s3 = grpc_mdstr_from_string("very much not hello");
@@ -70,9 +72,10 @@
   GPR_ASSERT(s3 != s1);
   GPR_ASSERT(grpc_slice_str_cmp(s1->slice, "hello") == 0);
   GPR_ASSERT(grpc_slice_str_cmp(s3->slice, "very much not hello") == 0);
-  GRPC_MDSTR_UNREF(s1);
-  GRPC_MDSTR_UNREF(s2);
-  GRPC_MDSTR_UNREF(s3);
+  GRPC_MDSTR_UNREF(&exec_ctx, s1);
+  GRPC_MDSTR_UNREF(&exec_ctx, s2);
+  GRPC_MDSTR_UNREF(&exec_ctx, s3);
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
@@ -82,9 +85,10 @@
   LOG_TEST("test_create_metadata");
 
   grpc_init();
-  m1 = grpc_mdelem_from_strings("a", "b");
-  m2 = grpc_mdelem_from_strings("a", "b");
-  m3 = grpc_mdelem_from_strings("a", "c");
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  m1 = grpc_mdelem_from_strings(&exec_ctx, "a", "b");
+  m2 = grpc_mdelem_from_strings(&exec_ctx, "a", "b");
+  m3 = grpc_mdelem_from_strings(&exec_ctx, "a", "c");
   GPR_ASSERT(m1 == m2);
   GPR_ASSERT(m3 != m1);
   GPR_ASSERT(m3->key == m1->key);
@@ -92,9 +96,10 @@
   GPR_ASSERT(grpc_slice_str_cmp(m1->key->slice, "a") == 0);
   GPR_ASSERT(grpc_slice_str_cmp(m1->value->slice, "b") == 0);
   GPR_ASSERT(grpc_slice_str_cmp(m3->value->slice, "c") == 0);
-  GRPC_MDELEM_UNREF(m1);
-  GRPC_MDELEM_UNREF(m2);
-  GRPC_MDELEM_UNREF(m3);
+  GRPC_MDELEM_UNREF(&exec_ctx, m1);
+  GRPC_MDELEM_UNREF(&exec_ctx, m2);
+  GRPC_MDELEM_UNREF(&exec_ctx, m3);
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
@@ -105,11 +110,14 @@
   LOG_TEST("test_create_many_ephemeral_metadata");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   /* add, and immediately delete a bunch of different elements */
   for (i = 0; i < MANY; i++) {
     gpr_ltoa(i, buffer);
-    GRPC_MDELEM_UNREF(grpc_mdelem_from_strings("a", buffer));
+    GRPC_MDELEM_UNREF(&exec_ctx,
+                      grpc_mdelem_from_strings(&exec_ctx, "a", buffer));
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
@@ -122,22 +130,24 @@
   LOG_TEST("test_create_many_persistant_metadata");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   /* add phase */
   for (i = 0; i < MANY; i++) {
     gpr_ltoa(i, buffer);
-    created[i] = grpc_mdelem_from_strings("a", buffer);
+    created[i] = grpc_mdelem_from_strings(&exec_ctx, "a", buffer);
   }
   /* verify phase */
   for (i = 0; i < MANY; i++) {
     gpr_ltoa(i, buffer);
-    md = grpc_mdelem_from_strings("a", buffer);
+    md = grpc_mdelem_from_strings(&exec_ctx, "a", buffer);
     GPR_ASSERT(md == created[i]);
-    GRPC_MDELEM_UNREF(md);
+    GRPC_MDELEM_UNREF(&exec_ctx, md);
   }
   /* cleanup phase */
   for (i = 0; i < MANY; i++) {
-    GRPC_MDELEM_UNREF(created[i]);
+    GRPC_MDELEM_UNREF(&exec_ctx, created[i]);
   }
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 
   gpr_free(created);
@@ -147,9 +157,11 @@
   LOG_TEST("test_spin_creating_the_same_thing");
 
   grpc_init();
-  GRPC_MDELEM_UNREF(grpc_mdelem_from_strings("a", "b"));
-  GRPC_MDELEM_UNREF(grpc_mdelem_from_strings("a", "b"));
-  GRPC_MDELEM_UNREF(grpc_mdelem_from_strings("a", "b"));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_from_strings(&exec_ctx, "a", "b"));
+  GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_from_strings(&exec_ctx, "a", "b"));
+  GRPC_MDELEM_UNREF(&exec_ctx, grpc_mdelem_from_strings(&exec_ctx, "a", "b"));
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
@@ -164,6 +176,7 @@
   LOG_TEST("test_things_stick_around");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   for (i = 0; i < nstrs; i++) {
     gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%" PRIuPTR "x", i);
@@ -174,7 +187,7 @@
 
   for (i = 0; i < nstrs; i++) {
     GRPC_MDSTR_REF(strs[i]);
-    GRPC_MDSTR_UNREF(strs[i]);
+    GRPC_MDSTR_UNREF(&exec_ctx, strs[i]);
   }
 
   for (i = 0; i < nstrs; i++) {
@@ -186,17 +199,18 @@
   }
 
   for (i = 0; i < nstrs; i++) {
-    GRPC_MDSTR_UNREF(strs[shuf[i]]);
+    GRPC_MDSTR_UNREF(&exec_ctx, strs[shuf[i]]);
     for (j = i + 1; j < nstrs; j++) {
       gpr_asprintf(&buffer, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx%" PRIuPTR "x",
                    shuf[j]);
       test = grpc_mdstr_from_string(buffer);
       GPR_ASSERT(test == strs[shuf[j]]);
-      GRPC_MDSTR_UNREF(test);
+      GRPC_MDSTR_UNREF(&exec_ctx, test);
       gpr_free(buffer);
     }
   }
 
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
   gpr_free(strs);
   gpr_free(shuf);
@@ -210,19 +224,21 @@
   LOG_TEST("test_slices_work");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   str = grpc_mdstr_from_string(
       "123456789012345678901234567890123456789012345678901234567890");
   slice = grpc_slice_ref(str->slice);
-  GRPC_MDSTR_UNREF(str);
-  grpc_slice_unref(slice);
+  GRPC_MDSTR_UNREF(&exec_ctx, str);
+  grpc_slice_unref_internal(&exec_ctx, slice);
 
   str = grpc_mdstr_from_string(
       "123456789012345678901234567890123456789012345678901234567890");
   slice = grpc_slice_ref(str->slice);
-  grpc_slice_unref(slice);
-  GRPC_MDSTR_UNREF(str);
+  grpc_slice_unref_internal(&exec_ctx, slice);
+  GRPC_MDSTR_UNREF(&exec_ctx, str);
 
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
@@ -234,13 +250,15 @@
   LOG_TEST("test_base64_and_huffman_works");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   str = grpc_mdstr_from_string("abcdefg");
   slice1 = grpc_mdstr_as_base64_encoded_and_huffman_compressed(str);
   slice2 = grpc_chttp2_base64_encode_and_huffman_compress(str->slice);
   GPR_ASSERT(0 == grpc_slice_cmp(slice1, slice2));
 
-  grpc_slice_unref(slice2);
-  GRPC_MDSTR_UNREF(str);
+  grpc_slice_unref_internal(&exec_ctx, slice2);
+  GRPC_MDSTR_UNREF(&exec_ctx, str);
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
@@ -251,29 +269,33 @@
   LOG_TEST("test_user_data_works");
 
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   ud1 = gpr_malloc(sizeof(int));
   *ud1 = 1;
   ud2 = gpr_malloc(sizeof(int));
   *ud2 = 2;
-  md = grpc_mdelem_from_strings("abc", "123");
+  md = grpc_mdelem_from_strings(&exec_ctx, "abc", "123");
   grpc_mdelem_set_user_data(md, gpr_free, ud1);
   grpc_mdelem_set_user_data(md, gpr_free, ud2);
   GPR_ASSERT(grpc_mdelem_get_user_data(md, gpr_free) == ud1);
-  GRPC_MDELEM_UNREF(md);
+  GRPC_MDELEM_UNREF(&exec_ctx, md);
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
-static void verify_ascii_header_size(const char *key, const char *value) {
-  grpc_mdelem *elem = grpc_mdelem_from_strings(key, value);
+static void verify_ascii_header_size(grpc_exec_ctx *exec_ctx, const char *key,
+                                     const char *value) {
+  grpc_mdelem *elem = grpc_mdelem_from_strings(exec_ctx, key, value);
   size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
   size_t expected_size = 32 + strlen(key) + strlen(value);
   GPR_ASSERT(expected_size == elem_size);
-  GRPC_MDELEM_UNREF(elem);
+  GRPC_MDELEM_UNREF(exec_ctx, elem);
 }
 
-static void verify_binary_header_size(const char *key, const uint8_t *value,
-                                      size_t value_len) {
-  grpc_mdelem *elem = grpc_mdelem_from_string_and_buffer(key, value, value_len);
+static void verify_binary_header_size(grpc_exec_ctx *exec_ctx, const char *key,
+                                      const uint8_t *value, size_t value_len) {
+  grpc_mdelem *elem =
+      grpc_mdelem_from_string_and_buffer(exec_ctx, key, value, value_len);
   GPR_ASSERT(grpc_is_binary_header(key, strlen(key)));
   size_t elem_size = grpc_mdelem_get_size_in_hpack_table(elem);
   grpc_slice value_slice =
@@ -281,33 +303,37 @@
   grpc_slice base64_encoded = grpc_chttp2_base64_encode(value_slice);
   size_t expected_size = 32 + strlen(key) + GRPC_SLICE_LENGTH(base64_encoded);
   GPR_ASSERT(expected_size == elem_size);
-  grpc_slice_unref(value_slice);
-  grpc_slice_unref(base64_encoded);
-  GRPC_MDELEM_UNREF(elem);
+  grpc_slice_unref_internal(exec_ctx, value_slice);
+  grpc_slice_unref_internal(exec_ctx, base64_encoded);
+  GRPC_MDELEM_UNREF(exec_ctx, elem);
 }
 
 #define BUFFER_SIZE 64
 static void test_mdelem_sizes_in_hpack(void) {
   LOG_TEST("test_mdelem_size");
   grpc_init();
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   uint8_t binary_value[BUFFER_SIZE] = {0};
   for (uint8_t i = 0; i < BUFFER_SIZE; i++) {
     binary_value[i] = i;
   }
 
-  verify_ascii_header_size("hello", "world");
-  verify_ascii_header_size("hello", "worldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
-  verify_ascii_header_size(":scheme", "http");
+  verify_ascii_header_size(&exec_ctx, "hello", "world");
+  verify_ascii_header_size(&exec_ctx, "hello",
+                           "worldxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+  verify_ascii_header_size(&exec_ctx, ":scheme", "http");
 
   for (uint8_t i = 0; i < BUFFER_SIZE; i++) {
-    verify_binary_header_size("hello-bin", binary_value, i);
+    verify_binary_header_size(&exec_ctx, "hello-bin", binary_value, i);
   }
 
   const char *static_metadata = grpc_static_metadata_strings[0];
   memcpy(binary_value, static_metadata, strlen(static_metadata));
-  verify_binary_header_size("hello-bin", binary_value, strlen(static_metadata));
+  verify_binary_header_size(&exec_ctx, "hello-bin", binary_value,
+                            strlen(static_metadata));
 
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
 }
 
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
new file mode 100644
index 0000000..e50e595
--- /dev/null
+++ b/test/core/util/BUILD
@@ -0,0 +1,58 @@
+
+
+cc_library(
+    name = "gpr_test_util",
+    srcs = [
+        "test_config.c",
+        "memory_counters.c",
+    ],
+    hdrs = [
+        "test_config.h",
+        "memory_counters.h",
+    ],
+    deps = ["//:gpr"],
+    visibility = ["//:__subpackages__"],
+)
+
+cc_library(
+    name = "grpc_test_util",
+    srcs = [
+        "grpc_profiler.c",
+        "mock_endpoint.c",
+        "parse_hexstring.c",
+        "passthru_endpoint.c",
+        "port_posix.c",
+        "port_server_client.c",
+        "port_windows.c",
+        "reconnect_server.c",
+        "slice_splitter.c",
+        "test_tcp_server.c",
+    ],
+    hdrs = [
+        "grpc_profiler.h",
+        "mock_endpoint.h",
+        "parse_hexstring.h",
+        "passthru_endpoint.h",
+        "port.h",
+        "port_server_client.h",
+        "reconnect_server.h",
+        "slice_splitter.h",
+        "test_tcp_server.h",
+    ],
+    deps = [":gpr_test_util", "//:grpc"],
+    visibility = ["//test:__subpackages__"],
+    copts = ["-std=c99"],
+)
+
+cc_library(
+  name = "one_corpus_entry_fuzzer",
+  srcs = ["one_corpus_entry_fuzzer.c"],
+  deps = [":gpr_test_util", "//:grpc"],
+  visibility = ["//test:__subpackages__"],
+)
+
+sh_library(
+  name = "fuzzer_one_entry_runner",
+  srcs = ["fuzzer_one_entry_runner.sh"],
+  visibility = ["//test:__subpackages__"],
+)
diff --git a/src/python/grpcio_health_checking/grpc/__init__.py b/test/core/util/fuzzer_one_entry_runner.sh
old mode 100644
new mode 100755
similarity index 93%
rename from src/python/grpcio_health_checking/grpc/__init__.py
rename to test/core/util/fuzzer_one_entry_runner.sh
index fcc7048..a0558a9
--- a/src/python/grpcio_health_checking/grpc/__init__.py
+++ b/test/core/util/fuzzer_one_entry_runner.sh
@@ -1,4 +1,8 @@
-# Copyright 2015, Google Inc.
+#!/bin/sh
+
+# Test runner for fuzzer tests from bazel
+
+# Copyright 2017, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -26,5 +30,4 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-__import__('pkg_resources').declare_namespace(__name__)
+$1 $2
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/core/util/grpc_fuzzer.bzl
old mode 100755
new mode 100644
similarity index 73%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/core/util/grpc_fuzzer.bzl
index 7438713..2f552a9
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/core/util/grpc_fuzzer.bzl
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,17 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
-
-cd $(dirname $0)/../..
-
-make grpc_csharp_ext
-
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
+def grpc_fuzzer(name, corpus, srcs = [], deps = [], **kwargs):
+  native.cc_binary(
+    name = '%s/one_entry.bin' % name,
+    srcs = srcs,
+    deps = deps + ["//test/core/util:one_corpus_entry_fuzzer"],
+    **kwargs
+  )
+  for entry in native.glob(['%s/*' % corpus]):
+    native.sh_test(
+      name = '%s/one_entry/%s' % (name, entry),
+      data = [':%s/one_entry.bin' % name, entry],
+      srcs = ['//test/core/util:fuzzer_one_entry_runner'],
+      args = ['$(location :%s/one_entry.bin)' % name, '$(location %s)' % entry]
+    )
diff --git a/test/core/util/memory_counters.h b/test/core/util/memory_counters.h
index f332816..b9b2b3a 100644
--- a/test/core/util/memory_counters.h
+++ b/test/core/util/memory_counters.h
@@ -34,6 +34,8 @@
 #ifndef GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
 #define GRPC_TEST_CORE_UTIL_MEMORY_COUNTERS_H
 
+#include <stddef.h>
+
 struct grpc_memory_counters {
   size_t total_size_relative;
   size_t total_size_absolute;
diff --git a/test/core/util/mock_endpoint.c b/test/core/util/mock_endpoint.c
index bf6d852..04793bc 100644
--- a/test/core/util/mock_endpoint.c
+++ b/test/core/util/mock_endpoint.c
@@ -55,7 +55,7 @@
   gpr_mu_lock(&m->mu);
   if (m->read_buffer.count > 0) {
     grpc_slice_buffer_swap(&m->read_buffer, slices);
-    grpc_exec_ctx_sched(exec_ctx, cb, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_NONE);
   } else {
     m->on_read = cb;
     m->on_read_out = slices;
@@ -69,7 +69,7 @@
   for (size_t i = 0; i < slices->count; i++) {
     m->on_write(slices->slices[i]);
   }
-  grpc_exec_ctx_sched(exec_ctx, cb, GRPC_ERROR_NONE, NULL);
+  grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_NONE);
 }
 
 static void me_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -82,8 +82,8 @@
   grpc_mock_endpoint *m = (grpc_mock_endpoint *)ep;
   gpr_mu_lock(&m->mu);
   if (m->on_read) {
-    grpc_exec_ctx_sched(exec_ctx, m->on_read,
-                        GRPC_ERROR_CREATE("Endpoint Shutdown"), NULL);
+    grpc_closure_sched(exec_ctx, m->on_read,
+                       GRPC_ERROR_CREATE("Endpoint Shutdown"));
     m->on_read = NULL;
   }
   gpr_mu_unlock(&m->mu);
@@ -144,7 +144,7 @@
   gpr_mu_lock(&m->mu);
   if (m->on_read != NULL) {
     grpc_slice_buffer_add(m->on_read_out, slice);
-    grpc_exec_ctx_sched(exec_ctx, m->on_read, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, m->on_read, GRPC_ERROR_NONE);
     m->on_read = NULL;
   } else {
     grpc_slice_buffer_add(&m->read_buffer, slice);
diff --git a/test/core/util/passthru_endpoint.c b/test/core/util/passthru_endpoint.c
index b3405f02..d42ec7f 100644
--- a/test/core/util/passthru_endpoint.c
+++ b/test/core/util/passthru_endpoint.c
@@ -39,6 +39,8 @@
 #include <grpc/support/string_util.h>
 #include "src/core/lib/iomgr/sockaddr.h"
 
+#include "src/core/lib/slice/slice_internal.h"
+
 typedef struct passthru_endpoint passthru_endpoint;
 
 typedef struct {
@@ -63,11 +65,10 @@
   half *m = (half *)ep;
   gpr_mu_lock(&m->parent->mu);
   if (m->parent->shutdown) {
-    grpc_exec_ctx_sched(exec_ctx, cb, GRPC_ERROR_CREATE("Already shutdown"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_CREATE("Already shutdown"));
   } else if (m->read_buffer.count > 0) {
     grpc_slice_buffer_swap(&m->read_buffer, slices);
-    grpc_exec_ctx_sched(exec_ctx, cb, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, cb, GRPC_ERROR_NONE);
   } else {
     m->on_read = cb;
     m->on_read_out = slices;
@@ -91,7 +92,7 @@
     for (size_t i = 0; i < slices->count; i++) {
       grpc_slice_buffer_add(m->on_read_out, grpc_slice_ref(slices->slices[i]));
     }
-    grpc_exec_ctx_sched(exec_ctx, m->on_read, GRPC_ERROR_NONE, NULL);
+    grpc_closure_sched(exec_ctx, m->on_read, GRPC_ERROR_NONE);
     m->on_read = NULL;
   } else {
     for (size_t i = 0; i < slices->count; i++) {
@@ -99,7 +100,7 @@
     }
   }
   gpr_mu_unlock(&m->parent->mu);
-  grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+  grpc_closure_sched(exec_ctx, cb, error);
 }
 
 static void me_add_to_pollset(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep,
@@ -113,14 +114,12 @@
   gpr_mu_lock(&m->parent->mu);
   m->parent->shutdown = true;
   if (m->on_read) {
-    grpc_exec_ctx_sched(exec_ctx, m->on_read, GRPC_ERROR_CREATE("Shutdown"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, m->on_read, GRPC_ERROR_CREATE("Shutdown"));
     m->on_read = NULL;
   }
   m = other_half(m);
   if (m->on_read) {
-    grpc_exec_ctx_sched(exec_ctx, m->on_read, GRPC_ERROR_CREATE("Shutdown"),
-                        NULL);
+    grpc_closure_sched(exec_ctx, m->on_read, GRPC_ERROR_CREATE("Shutdown"));
     m->on_read = NULL;
   }
   gpr_mu_unlock(&m->parent->mu);
@@ -133,8 +132,8 @@
   if (0 == --p->halves) {
     gpr_mu_unlock(&p->mu);
     gpr_mu_destroy(&p->mu);
-    grpc_slice_buffer_destroy(&p->client.read_buffer);
-    grpc_slice_buffer_destroy(&p->server.read_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &p->client.read_buffer);
+    grpc_slice_buffer_destroy_internal(exec_ctx, &p->server.read_buffer);
     grpc_resource_user_unref(exec_ctx, p->client.resource_user);
     grpc_resource_user_unref(exec_ctx, p->server.resource_user);
     gpr_free(p);
diff --git a/test/core/util/port_server_client.c b/test/core/util/port_server_client.c
index b2342fe..4baf63d 100644
--- a/test/core/util/port_server_client.c
+++ b/test/core/util/port_server_client.c
@@ -92,7 +92,8 @@
   grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
   grpc_pollset_init(pollset, &pr.mu);
   pr.pops = grpc_polling_entity_create_from_pollset(pollset);
-  shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops);
+  shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops,
+                                         grpc_schedule_on_exec_ctx);
 
   req.host = server;
   gpr_asprintf(&path, "/drop/%d", port);
@@ -103,8 +104,10 @@
       grpc_resource_quota_create("port_server_client/free");
   grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req,
                    GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
-                   grpc_closure_create(freed_port_from_server, &pr), &rsp);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+                   grpc_closure_create(freed_port_from_server, &pr,
+                                       grpc_schedule_on_exec_ctx),
+                   &rsp);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   gpr_mu_lock(pr.mu);
   while (!pr.done) {
     grpc_pollset_worker *worker = NULL;
@@ -174,9 +177,10 @@
         grpc_resource_quota_create("port_server_client/pick_retry");
     grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pops, resource_quota, &req,
                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
-                     grpc_closure_create(got_port_from_server, pr),
+                     grpc_closure_create(got_port_from_server, pr,
+                                         grpc_schedule_on_exec_ctx),
                      &pr->response);
-    grpc_resource_quota_internal_unref(exec_ctx, resource_quota);
+    grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
     return;
   }
   GPR_ASSERT(response);
@@ -208,7 +212,8 @@
   grpc_pollset *pollset = gpr_malloc(grpc_pollset_size());
   grpc_pollset_init(pollset, &pr.mu);
   pr.pops = grpc_polling_entity_create_from_pollset(pollset);
-  shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops);
+  shutdown_closure = grpc_closure_create(destroy_pops_and_shutdown, &pr.pops,
+                                         grpc_schedule_on_exec_ctx);
   pr.port = -1;
   pr.server = server;
   pr.ctx = &context;
@@ -219,11 +224,12 @@
   grpc_httpcli_context_init(&context);
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("port_server_client/pick");
-  grpc_httpcli_get(&exec_ctx, &context, &pr.pops, resource_quota, &req,
-                   GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
-                   grpc_closure_create(got_port_from_server, &pr),
-                   &pr.response);
-  grpc_resource_quota_internal_unref(&exec_ctx, resource_quota);
+  grpc_httpcli_get(
+      &exec_ctx, &context, &pr.pops, resource_quota, &req,
+      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10),
+      grpc_closure_create(got_port_from_server, &pr, grpc_schedule_on_exec_ctx),
+      &pr.response);
+  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_exec_ctx_finish(&exec_ctx);
   gpr_mu_lock(pr.mu);
   while (pr.port == -1) {
diff --git a/test/core/util/test_tcp_server.c b/test/core/util/test_tcp_server.c
index 16df91d..2338b81 100644
--- a/test/core/util/test_tcp_server.c
+++ b/test/core/util/test_tcp_server.c
@@ -57,7 +57,8 @@
                           grpc_tcp_server_cb on_connect, void *user_data) {
   grpc_init();
   server->tcp_server = NULL;
-  grpc_closure_init(&server->shutdown_complete, on_server_destroyed, server);
+  grpc_closure_init(&server->shutdown_complete, on_server_destroyed, server,
+                    grpc_schedule_on_exec_ctx);
   server->shutdown = 0;
   server->pollset = gpr_malloc(grpc_pollset_size());
   grpc_pollset_init(server->pollset, &server->mu);
@@ -111,7 +112,8 @@
   gpr_timespec shutdown_deadline;
   grpc_closure do_nothing_cb;
   grpc_tcp_server_unref(&exec_ctx, server->tcp_server);
-  grpc_closure_init(&do_nothing_cb, do_nothing, NULL);
+  grpc_closure_init(&do_nothing_cb, do_nothing, NULL,
+                    grpc_schedule_on_exec_ctx);
   shutdown_deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                                    gpr_time_from_seconds(5, GPR_TIMESPAN));
   while (!server->shutdown &&
diff --git a/test/cpp/common/channel_arguments_test.cc b/test/cpp/common/channel_arguments_test.cc
index 60d3215..190d32c 100644
--- a/test/cpp/common/channel_arguments_test.cc
+++ b/test/cpp/common/channel_arguments_test.cc
@@ -37,7 +37,11 @@
 #include <grpc/grpc.h>
 #include <grpc/support/useful.h>
 #include <gtest/gtest.h>
+
+extern "C" {
+#include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
+}
 
 namespace grpc {
 namespace testing {
@@ -228,7 +232,11 @@
   EXPECT_FALSE(HasArg(arg0));
 
   // arg0 is destroyed by grpc_socket_mutator_to_arg(mutator1)
-  arg1.value.pointer.vtable->destroy(arg1.value.pointer.p);
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    arg1.value.pointer.vtable->destroy(&exec_ctx, arg1.value.pointer.p);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
 }
 
 TEST_F(ChannelArgumentsTest, SetUserAgentPrefix) {
diff --git a/test/cpp/common/channel_filter_test.cc b/test/cpp/common/channel_filter_test.cc
index 600a953..32246a4 100644
--- a/test/cpp/common/channel_filter_test.cc
+++ b/test/cpp/common/channel_filter_test.cc
@@ -41,14 +41,24 @@
 
 class MyChannelData : public ChannelData {
  public:
-  MyChannelData(const grpc_channel_args& args, const char* peer)
-      : ChannelData(args, peer) {}
+  MyChannelData() {}
+
+  grpc_error* Init(grpc_exec_ctx* exec_ctx,
+                   grpc_channel_element_args* args) override {
+    (void)args->channel_args;  // Make sure field is available.
+    return GRPC_ERROR_NONE;
+  }
 };
 
 class MyCallData : public CallData {
  public:
-  explicit MyCallData(const ChannelData& channel_data)
-      : CallData(channel_data) {}
+  MyCallData() {}
+
+  grpc_error* Init(grpc_exec_ctx* exec_ctx, ChannelData* channel_data,
+                   grpc_call_element_args* args) override {
+    (void)args->path;  // Make sure field is available.
+    return GRPC_ERROR_NONE;
+  }
 };
 
 // This test ensures that when we make changes to the filter API in
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 8e385d1..2ce3f2f 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -254,7 +254,8 @@
 
     // Setup server
     ServerBuilder builder;
-    auto server_creds = GetServerCredentials(GetParam().credentials_type);
+    auto server_creds = GetCredentialsProvider()->GetServerCredentials(
+        GetParam().credentials_type);
     builder.AddListeningPort(server_address_.str(), server_creds);
     builder.RegisterService(&service_);
     cq_ = builder.AddCompletionQueue();
@@ -283,8 +284,8 @@
 
   void ResetStub() {
     ChannelArguments args;
-    auto channel_creds =
-        GetChannelCredentials(GetParam().credentials_type, &args);
+    auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
+        GetParam().credentials_type, &args);
     std::shared_ptr<Channel> channel =
         CreateCustomChannel(server_address_.str(), channel_creds, args);
     stub_ = grpc::testing::EchoTestService::NewStub(channel);
@@ -892,8 +893,8 @@
 
 TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
   ChannelArguments args;
-  auto channel_creds =
-      GetChannelCredentials(GetParam().credentials_type, &args);
+  auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
+      GetParam().credentials_type, &args);
   std::shared_ptr<Channel> channel =
       CreateCustomChannel(server_address_.str(), channel_creds, args);
   std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
@@ -1404,11 +1405,15 @@
   std::vector<grpc::string> credentials_types;
   std::vector<grpc::string> messages;
 
-  credentials_types.push_back(kInsecureCredentialsType);
-  auto sec_list = GetSecureCredentialsTypeList();
+  if (GetCredentialsProvider()->GetChannelCredentials(kInsecureCredentialsType,
+                                                      nullptr) != nullptr) {
+    credentials_types.push_back(kInsecureCredentialsType);
+  }
+  auto sec_list = GetCredentialsProvider()->GetSecureCredentialsTypeList();
   for (auto sec = sec_list.begin(); sec != sec_list.end(); sec++) {
     credentials_types.push_back(*sec);
   }
+  GPR_ASSERT(!credentials_types.empty());
 
   messages.push_back("Hello");
   for (int sz = 1; sz < test_big_limit; sz *= 2) {
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 9bb892c..1a1a94e 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -242,7 +242,8 @@
     // Setup server
     ServerBuilder builder;
     ConfigureServerBuilder(&builder);
-    auto server_creds = GetServerCredentials(GetParam().credentials_type);
+    auto server_creds = GetCredentialsProvider()->GetServerCredentials(
+        GetParam().credentials_type);
     if (GetParam().credentials_type != kInsecureCredentialsType) {
       server_creds->SetAuthMetadataProcessor(processor);
     }
@@ -270,8 +271,8 @@
     }
     EXPECT_TRUE(is_server_started_);
     ChannelArguments args;
-    auto channel_creds =
-        GetChannelCredentials(GetParam().credentials_type, &args);
+    auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
+        GetParam().credentials_type, &args);
     if (!user_agent_prefix_.empty()) {
       args.SetUserAgentPrefix(user_agent_prefix_);
     }
@@ -1520,11 +1521,18 @@
   std::vector<TestScenario> scenarios;
   std::vector<grpc::string> credentials_types;
   if (test_secure) {
-    credentials_types = GetSecureCredentialsTypeList();
+    credentials_types =
+        GetCredentialsProvider()->GetSecureCredentialsTypeList();
   }
   if (test_insecure) {
-    credentials_types.push_back(kInsecureCredentialsType);
+    // Only add insecure credentials type when it is registered with the
+    // provider. User may create providers that do not have insecure.
+    if (GetCredentialsProvider()->GetChannelCredentials(
+            kInsecureCredentialsType, nullptr) != nullptr) {
+      credentials_types.push_back(kInsecureCredentialsType);
+    }
   }
+  GPR_ASSERT(!credentials_types.empty());
   for (auto it = credentials_types.begin(); it != credentials_types.end();
        ++it) {
     scenarios.emplace_back(false, *it);
@@ -1541,7 +1549,7 @@
 
 INSTANTIATE_TEST_CASE_P(End2endServerTryCancel, End2endServerTryCancelTest,
                         ::testing::ValuesIn(CreateTestScenarios(false, true,
-                                                                false)));
+                                                                true)));
 
 INSTANTIATE_TEST_CASE_P(ProxyEnd2end, ProxyEnd2endTest,
                         ::testing::ValuesIn(CreateTestScenarios(true, true,
diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc
index ab6ed46..bd384f6 100644
--- a/test/cpp/end2end/filter_end2end_test.cc
+++ b/test/cpp/end2end/filter_end2end_test.cc
@@ -114,20 +114,17 @@
 
 class ChannelDataImpl : public ChannelData {
  public:
-  ChannelDataImpl(const grpc_channel_args& args, const char* peer)
-      : ChannelData(args, peer) {
+  grpc_error* Init(grpc_exec_ctx* exec_ctx, grpc_channel_element_args* args) {
     IncrementConnectionCounter();
+    return GRPC_ERROR_NONE;
   }
 };
 
 class CallDataImpl : public CallData {
  public:
-  explicit CallDataImpl(const ChannelDataImpl& channel_data)
-      : CallData(channel_data) {}
-
   void StartTransportStreamOp(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                               TransportStreamOp* op) override {
-    // Incrementing the counter could be done from the ctor, but we want
+    // Incrementing the counter could be done from Init(), but we want
     // to test that the individual methods are actually called correctly.
     if (op->recv_initial_metadata() != nullptr) IncrementCallCounter();
     grpc_call_next_op(exec_ctx, elem, op->op());
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
index fcdcaba..de304b9 100644
--- a/test/cpp/grpclb/grpclb_test.cc
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -659,7 +659,7 @@
   char *server_uri;
   // The grpclb LB policy will be automatically selected by virtue of
   // the fact that the returned addresses are balancer addresses.
-  gpr_asprintf(&server_uri, "test:%s?lb_enabled=1",
+  gpr_asprintf(&server_uri, "test:///%s?lb_enabled=1",
                tf.lb_server.servers_hostport);
   setup_client(server_uri, &tf.client);
   gpr_free(server_uri);
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index c58910a..3265554 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -49,6 +49,7 @@
 #include "test/cpp/util/test_config.h"
 
 DEFINE_bool(use_tls, false, "Whether to use tls.");
+DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
 DEFINE_bool(use_test_ca, false, "False to use SSL roots for google");
 DEFINE_int32(server_port, 0, "Server port.");
 DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index c171969..91564e5 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -50,8 +50,10 @@
 #include "src/cpp/client/secure_credentials.h"
 #include "test/core/security/oauth2_utils.h"
 #include "test/cpp/util/create_test_channel.h"
+#include "test/cpp/util/test_credentials_provider.h"
 
 DECLARE_bool(use_tls);
+DECLARE_string(custom_credentials_type);
 DECLARE_bool(use_test_ca);
 DECLARE_int32(server_port);
 DECLARE_string(server_host);
@@ -114,8 +116,12 @@
     creds = AccessTokenCredentials(raw_token);
     GPR_ASSERT(creds);
   }
-  return CreateTestChannel(host_port, FLAGS_server_host_override, FLAGS_use_tls,
-                           !FLAGS_use_test_ca, creds);
+  if (FLAGS_custom_credentials_type.empty()) {
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_use_tls, !FLAGS_use_test_ca, creds);
+  } else {
+    return CreateTestChannel(host_port, FLAGS_custom_credentials_type, creds);
+  }
 }
 
 }  // namespace testing
diff --git a/test/cpp/interop/http2_client.cc b/test/cpp/interop/http2_client.cc
new file mode 100644
index 0000000..38aee43
--- /dev/null
+++ b/test/cpp/interop/http2_client.cc
@@ -0,0 +1,272 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <thread>
+
+#include <gflags/gflags.h>
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/transport/byte_stream.h"
+#include "src/proto/grpc/testing/messages.grpc.pb.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
+#include "test/cpp/interop/http2_client.h"
+
+#include "src/core/lib/support/string.h"
+#include "test/cpp/util/create_test_channel.h"
+#include "test/cpp/util/test_config.h"
+
+namespace grpc {
+namespace testing {
+
+namespace {
+const int kLargeRequestSize = 271828;
+const int kLargeResponseSize = 314159;
+}  // namespace
+
+Http2Client::ServiceStub::ServiceStub(std::shared_ptr<Channel> channel)
+    : channel_(channel) {
+  stub_ = TestService::NewStub(channel);
+}
+
+TestService::Stub* Http2Client::ServiceStub::Get() { return stub_.get(); }
+
+Http2Client::Http2Client(std::shared_ptr<Channel> channel)
+    : serviceStub_(channel), channel_(channel) {}
+
+bool Http2Client::AssertStatusCode(const Status& s, StatusCode expected_code) {
+  if (s.error_code() == expected_code) {
+    return true;
+  }
+
+  gpr_log(GPR_ERROR, "Error status code: %d (expected: %d), message: %s",
+          s.error_code(), expected_code, s.error_message().c_str());
+  abort();
+}
+
+bool Http2Client::DoRstAfterHeader() {
+  gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after header");
+
+  ClientContext context;
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+  Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
+  AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
+  GPR_ASSERT(!response.has_payload());  // no data should be received
+
+  gpr_log(GPR_DEBUG, "Done testing reset stream after header");
+  return true;
+}
+
+bool Http2Client::DoRstAfterData() {
+  gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream after data");
+
+  ClientContext context;
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+  Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
+  AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
+  GPR_ASSERT(response.has_payload());  // data should be received
+
+  gpr_log(GPR_DEBUG, "Done testing reset stream after data");
+  return true;
+}
+
+bool Http2Client::DoRstDuringData() {
+  gpr_log(GPR_DEBUG, "Sending RPC and expecting reset stream during data");
+
+  ClientContext context;
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+  Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
+  AssertStatusCode(s, grpc::StatusCode::UNKNOWN);
+  GPR_ASSERT(!response.has_payload());  // no data should be received
+
+  gpr_log(GPR_DEBUG, "Done testing reset stream during data");
+  return true;
+}
+
+bool Http2Client::DoGoaway() {
+  gpr_log(GPR_DEBUG, "Sending two RPCs and expecting goaway");
+
+  int numCalls = 2;
+  for (int i = 0; i < numCalls; i++) {
+    ClientContext context;
+    SimpleRequest request;
+    SimpleResponse response;
+    request.set_response_size(kLargeResponseSize);
+    grpc::string payload(kLargeRequestSize, '\0');
+    request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+    Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
+    AssertStatusCode(s, grpc::StatusCode::OK);
+    GPR_ASSERT(response.payload().body() ==
+               grpc::string(kLargeResponseSize, '\0'));
+  }
+
+  gpr_log(GPR_DEBUG, "Done testing goaway");
+  return true;
+}
+
+bool Http2Client::DoPing() {
+  gpr_log(GPR_DEBUG, "Sending RPC and expecting ping");
+
+  ClientContext context;
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+  Status s = serviceStub_.Get()->UnaryCall(&context, request, &response);
+  AssertStatusCode(s, grpc::StatusCode::OK);
+  GPR_ASSERT(response.payload().body() ==
+             grpc::string(kLargeResponseSize, '\0'));
+
+  gpr_log(GPR_DEBUG, "Done testing ping");
+  return true;
+}
+
+void Http2Client::MaxStreamsWorker(std::shared_ptr<grpc::Channel> channel) {
+  ClientContext context;
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+  Status s =
+      TestService::NewStub(channel)->UnaryCall(&context, request, &response);
+  AssertStatusCode(s, grpc::StatusCode::OK);
+  GPR_ASSERT(response.payload().body() ==
+             grpc::string(kLargeResponseSize, '\0'));
+}
+
+bool Http2Client::DoMaxStreams() {
+  gpr_log(GPR_DEBUG, "Testing max streams");
+
+  // Make an initial call on the channel to ensure the server's max streams
+  // setting is received
+  ClientContext context;
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request.mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+  Status s =
+      TestService::NewStub(channel_)->UnaryCall(&context, request, &response);
+  AssertStatusCode(s, grpc::StatusCode::OK);
+  GPR_ASSERT(response.payload().body() ==
+             grpc::string(kLargeResponseSize, '\0'));
+
+  std::vector<std::thread> test_threads;
+
+  for (int i = 0; i < 10; i++) {
+    test_threads.emplace_back(
+        std::thread(&Http2Client::MaxStreamsWorker, this, channel_));
+  }
+
+  for (auto it = test_threads.begin(); it != test_threads.end(); it++) {
+    it->join();
+  }
+
+  gpr_log(GPR_DEBUG, "Done testing max streams");
+  return true;
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+DEFINE_int32(server_port, 0, "Server port.");
+DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
+DEFINE_string(test_case, "rst_after_header",
+              "Configure different test cases. Valid options are:\n\n"
+              "goaway\n"
+              "max_streams\n"
+              "ping\n"
+              "rst_after_data\n"
+              "rst_after_header\n"
+              "rst_during_data\n");
+
+int main(int argc, char** argv) {
+  grpc::testing::InitTest(&argc, &argv, true);
+  GPR_ASSERT(FLAGS_server_port);
+  const int host_port_buf_size = 1024;
+  char host_port[host_port_buf_size];
+  snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
+           FLAGS_server_port);
+  grpc::testing::Http2Client client(grpc::CreateTestChannel(host_port, false));
+  gpr_log(GPR_INFO, "Testing case: %s", FLAGS_test_case.c_str());
+  int ret = 0;
+  if (FLAGS_test_case == "rst_after_header") {
+    client.DoRstAfterHeader();
+  } else if (FLAGS_test_case == "rst_after_data") {
+    client.DoRstAfterData();
+  } else if (FLAGS_test_case == "rst_during_data") {
+    client.DoRstDuringData();
+  } else if (FLAGS_test_case == "goaway") {
+    client.DoGoaway();
+  } else if (FLAGS_test_case == "ping") {
+    client.DoPing();
+  } else if (FLAGS_test_case == "max_streams") {
+    client.DoMaxStreams();
+  } else {
+    const char* testcases[] = {
+        "goaway",         "max_streams",      "ping",
+        "rst_after_data", "rst_after_header", "rst_during_data"};
+    char* joined_testcases =
+        gpr_strjoin_sep(testcases, GPR_ARRAY_SIZE(testcases), "\n", NULL);
+
+    gpr_log(GPR_ERROR, "Unsupported test case %s. Valid options are\n%s",
+            FLAGS_test_case.c_str(), joined_testcases);
+    gpr_free(joined_testcases);
+    ret = 1;
+  }
+
+  return ret;
+}
diff --git a/test/cpp/interop/http2_client.h b/test/cpp/interop/http2_client.h
new file mode 100644
index 0000000..6a315f5
--- /dev/null
+++ b/test/cpp/interop/http2_client.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_TEST_CPP_INTEROP_HTTP2_CLIENT_H
+#define GRPC_TEST_CPP_INTEROP_HTTP2_CLIENT_H
+
+#include <memory>
+
+#include <grpc++/channel.h>
+#include <grpc/grpc.h>
+#include "src/proto/grpc/testing/messages.grpc.pb.h"
+#include "src/proto/grpc/testing/test.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+class Http2Client {
+ public:
+  explicit Http2Client(std::shared_ptr<Channel> channel);
+  ~Http2Client() {}
+
+  bool DoRstAfterHeader();
+  bool DoRstAfterData();
+  bool DoRstDuringData();
+  bool DoGoaway();
+  bool DoPing();
+  bool DoMaxStreams();
+
+ private:
+  class ServiceStub {
+   public:
+    ServiceStub(std::shared_ptr<Channel> channel);
+
+    TestService::Stub* Get();
+
+   private:
+    std::unique_ptr<TestService::Stub> stub_;
+    std::shared_ptr<Channel> channel_;
+  };
+
+  void MaxStreamsWorker(std::shared_ptr<grpc::Channel> channel);
+  bool AssertStatusCode(const Status& s, StatusCode expected_code);
+  ServiceStub serviceStub_;
+  std::shared_ptr<Channel> channel_;
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_INTEROP_HTTP2_CLIENT_H
diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc
index 67456ce..956840b 100644
--- a/test/cpp/interop/interop_server.cc
+++ b/test/cpp/interop/interop_server.cc
@@ -56,6 +56,7 @@
 #include "test/cpp/util/test_config.h"
 
 DEFINE_bool(use_tls, false, "Whether to use tls.");
+DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
 DEFINE_int32(port, 0, "Server port.");
 DEFINE_int32(max_send_message_size, -1, "The maximum send message size.");
 
diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc
index 8b0b511..d395f50 100644
--- a/test/cpp/interop/server_helper.cc
+++ b/test/cpp/interop/server_helper.cc
@@ -39,23 +39,23 @@
 #include <grpc++/security/server_credentials.h>
 
 #include "src/core/lib/surface/call_test_only.h"
-#include "test/core/end2end/data/ssl_test_data.h"
+#include "test/cpp/util/test_credentials_provider.h"
 
 DECLARE_bool(use_tls);
+DECLARE_string(custom_credentials_type);
 
 namespace grpc {
 namespace testing {
 
 std::shared_ptr<ServerCredentials> CreateInteropServerCredentials() {
-  if (FLAGS_use_tls) {
-    SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
-                                                        test_server1_cert};
-    SslServerCredentialsOptions ssl_opts;
-    ssl_opts.pem_root_certs = "";
-    ssl_opts.pem_key_cert_pairs.push_back(pkcp);
-    return SslServerCredentials(ssl_opts);
+  if (!FLAGS_custom_credentials_type.empty()) {
+    return GetCredentialsProvider()->GetServerCredentials(
+        FLAGS_custom_credentials_type);
+  } else if (FLAGS_use_tls) {
+    return GetCredentialsProvider()->GetServerCredentials(kTlsCredentialsType);
   } else {
-    return InsecureServerCredentials();
+    return GetCredentialsProvider()->GetServerCredentials(
+        kInsecureCredentialsType);
   }
 }
 
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index fc35db52..562522d 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -147,6 +147,7 @@
 // Options from client.cc (for compatibility with interop test).
 // TODO(sreek): Consolidate overlapping options
 DEFINE_bool(use_tls, false, "Whether to use tls.");
+DEFINE_string(custom_credentials_type, "", "User provided credentials type.");
 DEFINE_bool(use_test_ca, false, "False to use SSL roots for google");
 DEFINE_int32(server_port, 0, "Server port.");
 DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
@@ -371,9 +372,9 @@
   }
 
   // Start metrics server before waiting for the stress test threads
+  std::unique_ptr<grpc::Server> metrics_server;
   if (FLAGS_metrics_port > 0) {
-    std::unique_ptr<grpc::Server> metrics_server =
-        metrics_service.StartServer(FLAGS_metrics_port);
+    metrics_server = metrics_service.StartServer(FLAGS_metrics_port);
   }
 
   // Wait for the stress test threads to complete
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index fdd78eb..18f9778 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -409,6 +409,7 @@
       // old compilers happy with using this in std::vector
       ChannelArguments args;
       args.SetInt("shard_to_ensure_no_subchannel_merges", shard);
+      set_channel_args(config, &args);
       channel_ = CreateTestChannel(
           target, config.security_params().server_host_override(),
           config.has_security_params(), !config.security_params().use_test_ca(),
@@ -423,6 +424,18 @@
     StubType* get_stub() { return stub_.get(); }
 
    private:
+    void set_channel_args(const ClientConfig& config, ChannelArguments* args) {
+      for (auto channel_arg : config.channel_args()) {
+        if (channel_arg.value_case() == ChannelArg::kStrValue) {
+          args->SetString(channel_arg.name(), channel_arg.str_value());
+        } else if (channel_arg.value_case() == ChannelArg::kIntValue) {
+          args->SetInt(channel_arg.name(), channel_arg.int_value());
+        } else {
+          gpr_log(GPR_ERROR, "Empty channel arg value.");
+        }
+      }
+    }
+
     std::shared_ptr<Channel> channel_;
     std::unique_ptr<StubType> stub_;
   };
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 22b2cd0..93ef32d 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -44,6 +44,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/support/env.h"
@@ -99,23 +100,36 @@
   return hosts;
 }
 
-static deque<string> get_workers(const string& name) {
-  char* env = gpr_getenv(name.c_str());
-  if (!env || strlen(env) == 0) return deque<string>();
-
+static deque<string> get_workers(const string& env_name) {
+  char* env = gpr_getenv(env_name.c_str());
+  if (!env) {
+    env = gpr_strdup("");
+  }
   deque<string> out;
   char* p = env;
-  for (;;) {
-    char* comma = strchr(p, ',');
-    if (comma) {
-      out.emplace_back(p, comma);
-      p = comma + 1;
-    } else {
-      out.emplace_back(p);
-      gpr_free(env);
-      return out;
+  if (strlen(env) != 0) {
+    for (;;) {
+      char* comma = strchr(p, ',');
+      if (comma) {
+        out.emplace_back(p, comma);
+        p = comma + 1;
+      } else {
+        out.emplace_back(p);
+        break;
+      }
     }
   }
+  if (out.size() == 0) {
+    gpr_log(GPR_ERROR,
+            "Environment variable \"%s\" does not contain a list of QPS "
+            "workers to use. Set it to a comma-separated list of "
+            "hostname:port pairs, starting with hosts that should act as "
+            "servers. E.g. export "
+            "%s=\"serverhost1:1234,clienthost1:1234,clienthost2:1234\"",
+            env_name.c_str(), env_name.c_str());
+  }
+  gpr_free(env);
+  return out;
 }
 
 // helpers for postprocess_scenario_result
@@ -195,7 +209,8 @@
 std::unique_ptr<ScenarioResult> RunScenario(
     const ClientConfig& initial_client_config, size_t num_clients,
     const ServerConfig& initial_server_config, size_t num_servers,
-    int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count) {
+    int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
+    const char* qps_server_target_override, bool configure_core_lists) {
   // Log everything from the driver
   gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
 
@@ -240,9 +255,7 @@
       workers.push_back(addr);
     }
   }
-
-  // Setup the hosts and core counts
-  auto hosts_cores = get_hosts_and_cores(workers);
+  GPR_ASSERT(workers.size() != 0);
 
   // if num_clients is set to <=0, do dynamic sizing: all workers
   // except for servers are clients
@@ -264,6 +277,11 @@
     unique_ptr<ClientReaderWriter<ServerArgs, ServerStatus>> stream;
   };
   std::vector<ServerData> servers(num_servers);
+  std::unordered_map<string, std::deque<int>> hosts_cores;
+
+  if (configure_core_lists) {
+    hosts_cores = get_hosts_and_cores(workers);
+  }
   for (size_t i = 0; i < num_servers; i++) {
     gpr_log(GPR_INFO, "Starting server on %s (worker #%" PRIuPTR ")",
             workers[i].c_str(), i);
@@ -271,37 +289,36 @@
         CreateChannel(workers[i], InsecureChannelCredentials()));
 
     ServerConfig server_config = initial_server_config;
-    char* host;
-    char* driver_port;
-    char* cli_target;
-    gpr_split_host_port(workers[i].c_str(), &host, &driver_port);
-    string host_str(host);
     int server_core_limit = initial_server_config.core_limit();
     int client_core_limit = initial_client_config.core_limit();
 
-    if (server_core_limit == 0 && client_core_limit > 0) {
-      // In this case, limit the server cores if it matches the
-      // same host as one or more clients
-      const auto& dq = hosts_cores.at(host_str);
-      bool match = false;
-      int limit = dq.size();
-      for (size_t cli = 0; cli < num_clients; cli++) {
-        if (host_str == get_host(workers[cli + num_servers])) {
-          limit -= client_core_limit;
-          match = true;
+    if (configure_core_lists) {
+      string host_str(get_host(workers[i]));
+      if (server_core_limit == 0 && client_core_limit > 0) {
+        // In this case, limit the server cores if it matches the
+        // same host as one or more clients
+        const auto& dq = hosts_cores.at(host_str);
+        bool match = false;
+        int limit = dq.size();
+        for (size_t cli = 0; cli < num_clients; cli++) {
+          if (host_str == get_host(workers[cli + num_servers])) {
+            limit -= client_core_limit;
+            match = true;
+          }
+        }
+        if (match) {
+          GPR_ASSERT(limit > 0);
+          server_core_limit = limit;
         }
       }
-      if (match) {
-        GPR_ASSERT(limit > 0);
-        server_core_limit = limit;
-      }
-    }
-    if (server_core_limit > 0) {
-      auto& dq = hosts_cores.at(host_str);
-      GPR_ASSERT(dq.size() >= static_cast<size_t>(server_core_limit));
-      for (int core = 0; core < server_core_limit; core++) {
-        server_config.add_core_list(dq.front());
-        dq.pop_front();
+      if (server_core_limit > 0) {
+        auto& dq = hosts_cores.at(host_str);
+        GPR_ASSERT(dq.size() >= static_cast<size_t>(server_core_limit));
+        gpr_log(GPR_INFO, "Setting server core_list");
+        for (int core = 0; core < server_core_limit; core++) {
+          server_config.add_core_list(dq.front());
+          dq.pop_front();
+        }
       }
     }
 
@@ -315,11 +332,19 @@
     if (!servers[i].stream->Read(&init_status)) {
       gpr_log(GPR_ERROR, "Server %zu did not yield initial status", i);
     }
-    gpr_join_host_port(&cli_target, host, init_status.port());
-    client_config.add_server_targets(cli_target);
-    gpr_free(host);
-    gpr_free(driver_port);
-    gpr_free(cli_target);
+    if (qps_server_target_override != NULL &&
+        strlen(qps_server_target_override) > 0) {
+      // overriding the qps server target only works if there is 1 server
+      GPR_ASSERT(num_servers == 1);
+      client_config.add_server_targets(qps_server_target_override);
+    } else {
+      std::string host;
+      char* cli_target;
+      host = get_host(workers[i]);
+      gpr_join_host_port(&cli_target, host.c_str(), init_status.port());
+      client_config.add_server_targets(cli_target);
+      gpr_free(cli_target);
+    }
   }
 
   // Targets are all set by now
@@ -341,7 +366,8 @@
 
     int server_core_limit = initial_server_config.core_limit();
     int client_core_limit = initial_client_config.core_limit();
-    if ((server_core_limit > 0) || (client_core_limit > 0)) {
+    if (configure_core_lists &&
+        ((server_core_limit > 0) || (client_core_limit > 0))) {
       auto& dq = hosts_cores.at(get_host(worker));
       if (client_core_limit == 0) {
         // limit client cores if it matches a server host
@@ -359,6 +385,7 @@
       }
       if (client_core_limit > 0) {
         GPR_ASSERT(dq.size() >= static_cast<size_t>(client_core_limit));
+        gpr_log(GPR_INFO, "Setting client core_list");
         for (int core = 0; core < client_core_limit; core++) {
           per_client_config.add_core_list(dq.front());
           dq.pop_front();
@@ -548,6 +575,9 @@
   // Get client, server lists
   bool result = true;
   auto workers = get_workers("QPS_WORKERS");
+  if (workers.size() == 0) {
+    return false;
+  }
   for (size_t i = 0; i < workers.size(); i++) {
     auto stub = WorkerService::NewStub(
         CreateChannel(workers[i], InsecureChannelCredentials()));
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index 93f4370..b5c8152 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -45,7 +45,9 @@
 std::unique_ptr<ScenarioResult> RunScenario(
     const grpc::testing::ClientConfig& client_config, size_t num_clients,
     const grpc::testing::ServerConfig& server_config, size_t num_servers,
-    int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count);
+    int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count,
+    const char* qps_server_target_override = "",
+    bool configure_core_lists = true);
 
 bool RunQuit();
 }  // namespace testing
diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc
index 31b5917..57ee5ef 100644
--- a/test/cpp/qps/qps_json_driver.cc
+++ b/test/cpp/qps/qps_json_driver.cc
@@ -67,17 +67,25 @@
               "range is narrower than the error_tolerance computed range, we "
               "stop the search.");
 
+DEFINE_string(qps_server_target_override, "",
+              "Override QPS server target to configure in client configs."
+              "Only applicable if there is a single benchmark server.");
+DEFINE_bool(configure_core_lists, true,
+            "Provide 'core_list' parameters to workers. Value determined "
+            "by cores available and 'core_limit' parameters of the scenarios.");
+
 namespace grpc {
 namespace testing {
 
 static std::unique_ptr<ScenarioResult> RunAndReport(const Scenario& scenario,
                                                     bool* success) {
   std::cerr << "RUNNING SCENARIO: " << scenario.name() << "\n";
-  auto result =
-      RunScenario(scenario.client_config(), scenario.num_clients(),
-                  scenario.server_config(), scenario.num_servers(),
-                  scenario.warmup_seconds(), scenario.benchmark_seconds(),
-                  scenario.spawn_local_worker_count());
+  auto result = RunScenario(
+      scenario.client_config(), scenario.num_clients(),
+      scenario.server_config(), scenario.num_servers(),
+      scenario.warmup_seconds(), scenario.benchmark_seconds(),
+      scenario.spawn_local_worker_count(),
+      FLAGS_qps_server_target_override.c_str(), FLAGS_configure_core_lists);
 
   // Amend the result with scenario config. Eventually we should adjust
   // RunScenario contract so we don't need to touch the result here.
@@ -204,6 +212,7 @@
             SearchOfferedLoad(FLAGS_initial_search_value,
                               FLAGS_targeted_cpu_load, scenario, &success);
         gpr_log(GPR_INFO, "targeted_offered_load %f", targeted_offered_load);
+        GetCpuLoad(scenario, targeted_offered_load, &success);
       } else {
         gpr_log(GPR_ERROR, "Unimplemented search param");
       }
diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc
index fe8b5d5..ad62e03 100644
--- a/test/cpp/util/create_test_channel.cc
+++ b/test/cpp/util/create_test_channel.cc
@@ -35,11 +35,37 @@
 
 #include <grpc++/create_channel.h>
 #include <grpc++/security/credentials.h>
+#include <grpc/support/log.h>
 
-#include "test/core/end2end/data/ssl_test_data.h"
+#include "test/cpp/util/test_credentials_provider.h"
 
 namespace grpc {
 
+namespace {
+
+const char kProdTlsCredentialsType[] = "prod_ssl";
+
+class SslCredentialProvider : public testing::CredentialTypeProvider {
+ public:
+  std::shared_ptr<ChannelCredentials> GetChannelCredentials(
+      grpc::ChannelArguments* args) override {
+    return SslCredentials(SslCredentialsOptions());
+  }
+  std::shared_ptr<ServerCredentials> GetServerCredentials() override {
+    return nullptr;
+  }
+};
+
+gpr_once g_once_init_add_prod_ssl_provider = GPR_ONCE_INIT;
+// Register ssl with non-test roots type to the credentials provider.
+void AddProdSslType() {
+  testing::GetCredentialsProvider()->AddSecureType(
+      kProdTlsCredentialsType, std::unique_ptr<testing::CredentialTypeProvider>(
+                                   new SslCredentialProvider));
+}
+
+}  // namespace
+
 // When ssl is enabled, if server is empty, override_hostname is used to
 // create channel. Otherwise, connect to server and override hostname if
 // override_hostname is provided.
@@ -61,16 +87,22 @@
     const std::shared_ptr<CallCredentials>& creds,
     const ChannelArguments& args) {
   ChannelArguments channel_args(args);
+  std::shared_ptr<ChannelCredentials> channel_creds;
   if (enable_ssl) {
-    const char* roots_certs = use_prod_roots ? "" : test_root_cert;
-    SslCredentialsOptions ssl_opts = {roots_certs, "", ""};
-
-    std::shared_ptr<ChannelCredentials> channel_creds =
-        SslCredentials(ssl_opts);
-
-    if (!server.empty() && !override_hostname.empty()) {
-      channel_args.SetSslTargetNameOverride(override_hostname);
+    if (use_prod_roots) {
+      gpr_once_init(&g_once_init_add_prod_ssl_provider, &AddProdSslType);
+      channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
+          kProdTlsCredentialsType, &channel_args);
+      if (!server.empty() && !override_hostname.empty()) {
+        channel_args.SetSslTargetNameOverride(override_hostname);
+      }
+    } else {
+      // override_hostname is discarded as the provider handles it.
+      channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
+          testing::kTlsCredentialsType, &channel_args);
     }
+    GPR_ASSERT(channel_creds != nullptr);
+
     const grpc::string& connect_to =
         server.empty() ? override_hostname : server;
     if (creds.get()) {
@@ -103,4 +135,18 @@
   return CreateTestChannel(server, "foo.test.google.fr", enable_ssl, false);
 }
 
+std::shared_ptr<Channel> CreateTestChannel(
+    const grpc::string& server, const grpc::string& credential_type,
+    const std::shared_ptr<CallCredentials>& creds) {
+  ChannelArguments channel_args;
+  std::shared_ptr<ChannelCredentials> channel_creds =
+      testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,
+                                                               &channel_args);
+  GPR_ASSERT(channel_creds != nullptr);
+  if (creds.get()) {
+    channel_creds = CompositeChannelCredentials(channel_creds, creds);
+  }
+  return CreateCustomChannel(server, channel_creds, channel_args);
+}
+
 }  // namespace grpc
diff --git a/test/cpp/util/create_test_channel.h b/test/cpp/util/create_test_channel.h
index 4ff666d..ce71a97 100644
--- a/test/cpp/util/create_test_channel.h
+++ b/test/cpp/util/create_test_channel.h
@@ -59,6 +59,10 @@
     const std::shared_ptr<CallCredentials>& creds,
     const ChannelArguments& args);
 
+std::shared_ptr<Channel> CreateTestChannel(
+    const grpc::string& server, const grpc::string& credential_type,
+    const std::shared_ptr<CallCredentials>& creds);
+
 }  // namespace grpc
 
 #endif  // GRPC_TEST_CPP_UTIL_CREATE_TEST_CHANNEL_H
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
index a3da568..b9900ca 100644
--- a/test/cpp/util/grpc_tool.cc
+++ b/test/cpp/util/grpc_tool.cc
@@ -86,11 +86,12 @@
   // callback);
   // bool PrintTypeId(int argc, const char** argv, GrpcToolOutputCallback
   // callback);
-  // bool ParseMessage(int argc, const char** argv, GrpcToolOutputCallback
-  // callback);
-  // bool ToText(int argc, const char** argv, GrpcToolOutputCallback callback);
-  // bool ToBinary(int argc, const char** argv, GrpcToolOutputCallback
-  // callback);
+  bool ParseMessage(int argc, const char** argv, const CliCredentials& cred,
+                    GrpcToolOutputCallback callback);
+  bool ToText(int argc, const char** argv, const CliCredentials& cred,
+              GrpcToolOutputCallback callback);
+  bool ToBinary(int argc, const char** argv, const CliCredentials& cred,
+                GrpcToolOutputCallback callback);
 
   void SetPrintCommandMode(int exit_status) {
     print_command_usage_ = true;
@@ -173,9 +174,9 @@
     {"list", BindWith5Args(&GrpcTool::ListServices), 1, 3},
     {"call", BindWith5Args(&GrpcTool::CallMethod), 2, 3},
     {"type", BindWith5Args(&GrpcTool::PrintType), 2, 2},
-    // {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
-    // {"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
-    // {"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
+    {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
+    {"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
+    {"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
 };
 
 void Usage(const grpc::string& msg) {
@@ -185,9 +186,9 @@
       "  grpc_cli ls ...         ; List services\n"
       "  grpc_cli call ...       ; Call method\n"
       "  grpc_cli type ...       ; Print type\n"
-      // "  grpc_cli parse ...      ; Parse message\n"
-      // "  grpc_cli totext ...     ; Convert binary message to text\n"
-      // "  grpc_cli tobinary ...   ; Convert text message to binary\n"
+      "  grpc_cli parse ...      ; Parse message\n"
+      "  grpc_cli totext ...     ; Convert binary message to text\n"
+      "  grpc_cli tobinary ...   ; Convert text message to binary\n"
       "  grpc_cli help ...       ; Print this message, or per-command usage\n"
       "\n",
       msg.c_str());
@@ -496,5 +497,122 @@
   return callback(output_ss.str());
 }
 
+bool GrpcTool::ParseMessage(int argc, const char** argv,
+                            const CliCredentials& cred,
+                            GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Parse message\n"
+      "  grpc_cli parse <address> <type> [<message>]\n"
+      "    <address>                ; host:port\n"
+      "    <type>                   ; Protocol buffer type name\n"
+      "    <message>                ; Text protobuffer (overrides --infile)\n"
+      "    --protofiles             ; Comma separated proto files used as a"
+      " fallback when parsing request/response\n"
+      "    --proto_path             ; The search path of proto files, valid"
+      " only when --protofiles is given\n"
+      "    --infile                 ; Input filename (defaults to stdin)\n"
+      "    --outfile                ; Output filename (defaults to stdout)\n"
+      "    --binary_input           ; Input in binary format\n"
+      "    --binary_output          ; Output in binary format\n" +
+      cred.GetCredentialUsage());
+
+  std::stringstream output_ss;
+  grpc::string message_text;
+  grpc::string server_address(argv[0]);
+  grpc::string type_name(argv[1]);
+  std::unique_ptr<grpc::testing::ProtoFileParser> parser;
+  grpc::string serialized_request_proto;
+
+  if (argc == 3) {
+    message_text = argv[2];
+    if (!FLAGS_infile.empty()) {
+      fprintf(stderr, "warning: message given in argv, ignoring --infile.\n");
+    }
+  } else {
+    std::stringstream input_stream;
+    if (FLAGS_infile.empty()) {
+      if (isatty(STDIN_FILENO)) {
+        fprintf(stderr, "reading request message from stdin...\n");
+      }
+      input_stream << std::cin.rdbuf();
+    } else {
+      std::ifstream input_file(FLAGS_infile, std::ios::in | std::ios::binary);
+      input_stream << input_file.rdbuf();
+      input_file.close();
+    }
+    message_text = input_stream.str();
+  }
+
+  if (!FLAGS_binary_input || !FLAGS_binary_output) {
+    std::shared_ptr<grpc::Channel> channel =
+        grpc::CreateChannel(server_address, cred.GetCredentials());
+    parser.reset(
+        new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr,
+                                           FLAGS_proto_path, FLAGS_protofiles));
+    if (parser->HasError()) {
+      return false;
+    }
+  }
+
+  if (FLAGS_binary_input) {
+    serialized_request_proto = message_text;
+  } else {
+    serialized_request_proto =
+        parser->GetSerializedProtoFromMessageType(type_name, message_text);
+    if (parser->HasError()) {
+      return false;
+    }
+  }
+
+  if (FLAGS_binary_output) {
+    output_ss << serialized_request_proto;
+  } else {
+    grpc::string output_text = parser->GetTextFormatFromMessageType(
+        type_name, serialized_request_proto);
+    if (parser->HasError()) {
+      return false;
+    }
+    output_ss << output_text << std::endl;
+  }
+
+  return callback(output_ss.str());
+}
+
+bool GrpcTool::ToText(int argc, const char** argv, const CliCredentials& cred,
+                      GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Convert binary message to text\n"
+      "  grpc_cli totext <protofiles> <type>\n"
+      "    <protofiles>             ; Comma separated list of proto files\n"
+      "    <type>                   ; Protocol buffer type name\n"
+      "    --proto_path             ; The search path of proto files\n"
+      "    --infile                 ; Input filename (defaults to stdin)\n"
+      "    --outfile                ; Output filename (defaults to stdout)\n");
+
+  FLAGS_protofiles = argv[0];
+  FLAGS_remotedb = false;
+  FLAGS_binary_input = true;
+  FLAGS_binary_output = false;
+  return ParseMessage(argc, argv, cred, callback);
+}
+
+bool GrpcTool::ToBinary(int argc, const char** argv, const CliCredentials& cred,
+                        GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Convert text message to binary\n"
+      "  grpc_cli tobinary <protofiles> <type> [<message>]\n"
+      "    <protofiles>             ; Comma separated list of proto files\n"
+      "    <type>                   ; Protocol buffer type name\n"
+      "    --proto_path             ; The search path of proto files\n"
+      "    --infile                 ; Input filename (defaults to stdin)\n"
+      "    --outfile                ; Output filename (defaults to stdout)\n");
+
+  FLAGS_protofiles = argv[0];
+  FLAGS_remotedb = false;
+  FLAGS_binary_input = false;
+  FLAGS_binary_output = true;
+  return ParseMessage(argc, argv, cred, callback);
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
index 1ff8172..33ce611 100644
--- a/test/cpp/util/grpc_tool_test.cc
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -86,9 +86,18 @@
   "  rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
   "{}\n"
 
+#define ECHO_RESPONSE_MESSAGE \
+  "message: \"echo\"\n"       \
+  "param {\n"                 \
+  "  host: \"localhost\"\n"   \
+  "  peer: \"peer\"\n"        \
+  "}\n\n"
+
 namespace grpc {
 namespace testing {
 
+DECLARE_bool(binary_input);
+DECLARE_bool(binary_output);
 DECLARE_bool(l);
 
 namespace {
@@ -338,6 +347,47 @@
   ShutdownServer();
 }
 
+TEST_F(GrpcToolTest, ParseCommand) {
+  // Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
+  // ECHO_RESPONSE_MESSAGE"
+  std::stringstream output_stream;
+  std::stringstream binary_output_stream;
+
+  const grpc::string server_address = SetUpServer();
+  const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
+                        "grpc.testing.EchoResponse", ECHO_RESPONSE_MESSAGE};
+
+  FLAGS_binary_input = false;
+  FLAGS_binary_output = false;
+  EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+                                   std::bind(PrintStream, &output_stream,
+                                             std::placeholders::_1)));
+  // Expected output: ECHO_RESPONSE_MESSAGE
+  EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE));
+
+  // Parse text message to binary message and then parse it back to text message
+  output_stream.str(grpc::string());
+  output_stream.clear();
+  FLAGS_binary_output = true;
+  EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+                                   std::bind(PrintStream, &output_stream,
+                                             std::placeholders::_1)));
+  grpc::string binary_data = output_stream.str();
+  output_stream.str(grpc::string());
+  output_stream.clear();
+  argv[4] = binary_data.c_str();
+  FLAGS_binary_input = true;
+  FLAGS_binary_output = false;
+  EXPECT_TRUE(0 == GrpcToolMainLib(5, argv, TestCliCredentials(),
+                                   std::bind(PrintStream, &output_stream,
+                                             std::placeholders::_1)));
+
+  // Expected output: ECHO_RESPONSE_MESSAGE
+  EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE));
+
+  ShutdownServer();
+}
+
 TEST_F(GrpcToolTest, TooFewArguments) {
   // Test input "grpc_cli call Echo"
   std::stringstream output_stream;
diff --git a/test/cpp/util/test_credentials_provider.cc b/test/cpp/util/test_credentials_provider.cc
index 0456b96..909b02a 100644
--- a/test/cpp/util/test_credentials_provider.cc
+++ b/test/cpp/util/test_credentials_provider.cc
@@ -43,25 +43,9 @@
 #include "test/core/end2end/data/ssl_test_data.h"
 
 namespace grpc {
+namespace testing {
 namespace {
 
-using grpc::testing::CredentialTypeProvider;
-
-// Provide test credentials. Thread-safe.
-class CredentialsProvider {
- public:
-  virtual ~CredentialsProvider() {}
-
-  virtual void AddSecureType(
-      const grpc::string& type,
-      std::unique_ptr<CredentialTypeProvider> type_provider) = 0;
-  virtual std::shared_ptr<ChannelCredentials> GetChannelCredentials(
-      const grpc::string& type, ChannelArguments* args) = 0;
-  virtual std::shared_ptr<ServerCredentials> GetServerCredentials(
-      const grpc::string& type) = 0;
-  virtual std::vector<grpc::string> GetSecureCredentialsTypeList() = 0;
-};
-
 class DefaultCredentialsProvider : public CredentialsProvider {
  public:
   ~DefaultCredentialsProvider() override {}
@@ -145,37 +129,21 @@
       added_secure_type_providers_;
 };
 
-gpr_once g_once_init_provider = GPR_ONCE_INIT;
 CredentialsProvider* g_provider = nullptr;
 
-void CreateDefaultProvider() { g_provider = new DefaultCredentialsProvider; }
-
-CredentialsProvider* GetProvider() {
-  gpr_once_init(&g_once_init_provider, &CreateDefaultProvider);
-  return g_provider;
-}
-
 }  // namespace
 
-namespace testing {
-
-void AddSecureType(const grpc::string& type,
-                   std::unique_ptr<CredentialTypeProvider> type_provider) {
-  GetProvider()->AddSecureType(type, std::move(type_provider));
+CredentialsProvider* GetCredentialsProvider() {
+  if (g_provider == nullptr) {
+    g_provider = new DefaultCredentialsProvider;
+  }
+  return g_provider;
 }
 
-std::shared_ptr<ChannelCredentials> GetChannelCredentials(
-    const grpc::string& type, ChannelArguments* args) {
-  return GetProvider()->GetChannelCredentials(type, args);
-}
-
-std::shared_ptr<ServerCredentials> GetServerCredentials(
-    const grpc::string& type) {
-  return GetProvider()->GetServerCredentials(type);
-}
-
-std::vector<grpc::string> GetSecureCredentialsTypeList() {
-  return GetProvider()->GetSecureCredentialsTypeList();
+void SetCredentialsProvider(CredentialsProvider* provider) {
+  // For now, forbids overriding provider.
+  GPR_ASSERT(g_provider == nullptr);
+  g_provider = provider;
 }
 
 }  // namespace testing
diff --git a/test/cpp/util/test_credentials_provider.h b/test/cpp/util/test_credentials_provider.h
index 1fb311e..0bc52eb 100644
--- a/test/cpp/util/test_credentials_provider.h
+++ b/test/cpp/util/test_credentials_provider.h
@@ -59,23 +59,39 @@
   virtual std::shared_ptr<ServerCredentials> GetServerCredentials() = 0;
 };
 
-// Add a secure type in addition to the defaults above
-// (kInsecureCredentialsType, kTlsCredentialsType) that can be returned from the
-// functions below.
-void AddSecureType(const grpc::string& type,
-                   std::unique_ptr<CredentialTypeProvider> type_provider);
+// Provide test credentials. Thread-safe.
+class CredentialsProvider {
+ public:
+  virtual ~CredentialsProvider() {}
 
-// Provide channel credentials according to the given type. Alter the channel
-// arguments if needed.
-std::shared_ptr<ChannelCredentials> GetChannelCredentials(
-    const grpc::string& type, ChannelArguments* args);
+  // Add a secure type in addition to the defaults. The default provider has
+  // (kInsecureCredentialsType, kTlsCredentialsType).
+  virtual void AddSecureType(
+      const grpc::string& type,
+      std::unique_ptr<CredentialTypeProvider> type_provider) = 0;
 
-// Provide server credentials according to the given type.
-std::shared_ptr<ServerCredentials> GetServerCredentials(
-    const grpc::string& type);
+  // Provide channel credentials according to the given type. Alter the channel
+  // arguments if needed. Return nullptr if type is not registered.
+  virtual std::shared_ptr<ChannelCredentials> GetChannelCredentials(
+      const grpc::string& type, ChannelArguments* args) = 0;
 
-// Provide a list of secure credentials type.
-std::vector<grpc::string> GetSecureCredentialsTypeList();
+  // Provide server credentials according to the given type.
+  // Return nullptr if type is not registered.
+  virtual std::shared_ptr<ServerCredentials> GetServerCredentials(
+      const grpc::string& type) = 0;
+
+  // Provide a list of secure credentials type.
+  virtual std::vector<grpc::string> GetSecureCredentialsTypeList() = 0;
+};
+
+// Get the current provider. Create a default one if not set.
+// Not thread-safe.
+CredentialsProvider* GetCredentialsProvider();
+
+// Set the global provider. Takes ownership. The previous set provider will be
+// destroyed.
+// Not thread-safe.
+void SetCredentialsProvider(CredentialsProvider* provider);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/http2_test/http2_base_server.py b/test/http2_test/http2_base_server.py
new file mode 100644
index 0000000..8de028c
--- /dev/null
+++ b/test/http2_test/http2_base_server.py
@@ -0,0 +1,204 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import messages_pb2
+import struct
+
+import h2
+import h2.connection
+import twisted
+import twisted.internet
+import twisted.internet.protocol
+
+_READ_CHUNK_SIZE = 16384
+_GRPC_HEADER_SIZE = 5
+
+class H2ProtocolBaseServer(twisted.internet.protocol.Protocol):
+  def __init__(self):
+    self._conn = h2.connection.H2Connection(client_side=False)
+    self._recv_buffer = {}
+    self._handlers = {}
+    self._handlers['ConnectionMade'] = self.on_connection_made_default
+    self._handlers['DataReceived'] = self.on_data_received_default
+    self._handlers['WindowUpdated'] = self.on_window_update_default
+    self._handlers['RequestReceived'] = self.on_request_received_default
+    self._handlers['SendDone'] = self.on_send_done_default
+    self._handlers['ConnectionLost'] = self.on_connection_lost
+    self._handlers['PingAcknowledged'] = self.on_ping_acknowledged_default
+    self._stream_status = {}
+    self._send_remaining = {}
+    self._outstanding_pings = 0
+
+  def set_handlers(self, handlers):
+    self._handlers = handlers
+
+  def connectionMade(self):
+    self._handlers['ConnectionMade']()
+
+  def connectionLost(self, reason):
+    self._handlers['ConnectionLost'](reason)
+
+  def on_connection_made_default(self):
+    logging.info('Connection Made')
+    self._conn.initiate_connection()
+    self.transport.setTcpNoDelay(True)
+    self.transport.write(self._conn.data_to_send())
+
+  def on_connection_lost(self, reason):
+    logging.info('Disconnected %s' % reason)
+
+  def dataReceived(self, data):
+    try:
+      events = self._conn.receive_data(data)
+    except h2.exceptions.ProtocolError:
+      # this try/except block catches exceptions due to race between sending
+      # GOAWAY and processing a response in flight.
+      return
+    if self._conn.data_to_send:
+      self.transport.write(self._conn.data_to_send())
+    for event in events:
+      if isinstance(event, h2.events.RequestReceived) and self._handlers.has_key('RequestReceived'):
+        logging.info('RequestReceived Event for stream: %d' % event.stream_id)
+        self._handlers['RequestReceived'](event)
+      elif isinstance(event, h2.events.DataReceived) and self._handlers.has_key('DataReceived'):
+        logging.info('DataReceived Event for stream: %d' % event.stream_id)
+        self._handlers['DataReceived'](event)
+      elif isinstance(event, h2.events.WindowUpdated) and self._handlers.has_key('WindowUpdated'):
+        logging.info('WindowUpdated Event for stream: %d' % event.stream_id)
+        self._handlers['WindowUpdated'](event)
+      elif isinstance(event, h2.events.PingAcknowledged) and self._handlers.has_key('PingAcknowledged'):
+        logging.info('PingAcknowledged Event')
+        self._handlers['PingAcknowledged'](event)
+    self.transport.write(self._conn.data_to_send())
+
+  def on_ping_acknowledged_default(self, event):
+    logging.info('ping acknowledged')
+    self._outstanding_pings -= 1
+
+  def on_data_received_default(self, event):
+    self._conn.acknowledge_received_data(len(event.data), event.stream_id)
+    self._recv_buffer[event.stream_id] += event.data
+
+  def on_request_received_default(self, event):
+    self._recv_buffer[event.stream_id] = ''
+    self._stream_id = event.stream_id
+    self._stream_status[event.stream_id] = True
+    self._conn.send_headers(
+      stream_id=event.stream_id,
+      headers=[
+          (':status', '200'),
+          ('content-type', 'application/grpc'),
+          ('grpc-encoding', 'identity'),
+          ('grpc-accept-encoding', 'identity,deflate,gzip'),
+      ],
+    )
+    self.transport.write(self._conn.data_to_send())
+
+  def on_window_update_default(self, event):
+    # send pending data, if any
+    self.default_send(event.stream_id)
+
+  def send_reset_stream(self):
+    self._conn.reset_stream(self._stream_id)
+    self.transport.write(self._conn.data_to_send())
+
+  def setup_send(self, data_to_send, stream_id):
+    logging.info('Setting up data to send for stream_id: %d' % stream_id)
+    self._send_remaining[stream_id] = len(data_to_send)
+    self._send_offset = 0
+    self._data_to_send = data_to_send
+    self.default_send(stream_id)
+
+  def default_send(self, stream_id):
+    if not self._send_remaining.has_key(stream_id):
+      # not setup to send data yet
+      return
+
+    while self._send_remaining[stream_id] > 0:
+      lfcw = self._conn.local_flow_control_window(stream_id)
+      if lfcw == 0:
+        break
+      chunk_size = min(lfcw, _READ_CHUNK_SIZE)
+      bytes_to_send = min(chunk_size, self._send_remaining[stream_id])
+      logging.info('flow_control_window = %d. sending [%d:%d] stream_id %d' %
+                    (lfcw, self._send_offset, self._send_offset + bytes_to_send,
+                    stream_id))
+      data = self._data_to_send[self._send_offset : self._send_offset + bytes_to_send]
+      try:
+        self._conn.send_data(stream_id, data, False)
+      except h2.exceptions.ProtocolError:
+        logging.info('Stream %d is closed' % stream_id)
+        break
+      self._send_remaining[stream_id] -= bytes_to_send
+      self._send_offset += bytes_to_send
+      if self._send_remaining[stream_id] == 0:
+        self._handlers['SendDone'](stream_id)
+
+  def default_ping(self):
+    logging.info('sending ping')
+    self._outstanding_pings += 1
+    self._conn.ping(b'\x00'*8)
+    self.transport.write(self._conn.data_to_send())
+
+  def on_send_done_default(self, stream_id):
+    if self._stream_status[stream_id]:
+      self._stream_status[stream_id] = False
+      self.default_send_trailer(stream_id)
+    else:
+      logging.error('Stream %d is already closed' % stream_id)
+
+  def default_send_trailer(self, stream_id):
+    logging.info('Sending trailer for stream id %d' % stream_id)
+    self._conn.send_headers(stream_id,
+      headers=[ ('grpc-status', '0') ],
+      end_stream=True
+    )
+    self.transport.write(self._conn.data_to_send())
+
+  @staticmethod
+  def default_response_data(response_size):
+    sresp = messages_pb2.SimpleResponse()
+    sresp.payload.body = b'\x00'*response_size
+    serialized_resp_proto = sresp.SerializeToString()
+    response_data = b'\x00' + struct.pack('i', len(serialized_resp_proto))[::-1] + serialized_resp_proto
+    return response_data
+
+  def parse_received_data(self, stream_id):
+    """ returns a grpc framed string of bytes containing response proto of the size
+    asked in request """
+    recv_buffer = self._recv_buffer[stream_id]
+    grpc_msg_size = struct.unpack('i',recv_buffer[1:5][::-1])[0]
+    if len(recv_buffer) != _GRPC_HEADER_SIZE + grpc_msg_size:
+      return None
+    req_proto_str = recv_buffer[5:5+grpc_msg_size]
+    sr = messages_pb2.SimpleRequest()
+    sr.ParseFromString(req_proto_str)
+    logging.info('Parsed request for stream %d: response_size=%s' % (stream_id, sr.response_size))
+    return sr
diff --git a/test/http2_test/http2_test_server.py b/test/http2_test/http2_test_server.py
new file mode 100644
index 0000000..abde343
--- /dev/null
+++ b/test/http2_test/http2_test_server.py
@@ -0,0 +1,104 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""HTTP2 Test Server"""
+
+import argparse
+import logging
+import twisted
+import twisted.internet
+import twisted.internet.endpoints
+import twisted.internet.reactor
+
+import http2_base_server
+import test_goaway
+import test_max_streams
+import test_ping
+import test_rst_after_data
+import test_rst_after_header
+import test_rst_during_data
+
+_TEST_CASE_MAPPING = {
+  'rst_after_header': test_rst_after_header.TestcaseRstStreamAfterHeader,
+  'rst_after_data': test_rst_after_data.TestcaseRstStreamAfterData,
+  'rst_during_data': test_rst_during_data.TestcaseRstStreamDuringData,
+  'goaway': test_goaway.TestcaseGoaway,
+  'ping': test_ping.TestcasePing,
+  'max_streams': test_max_streams.TestcaseSettingsMaxStreams,
+}
+
+class H2Factory(twisted.internet.protocol.Factory):
+  def __init__(self, testcase):
+    logging.info('Creating H2Factory for new connection.')
+    self._num_streams = 0
+    self._testcase = testcase
+
+  def buildProtocol(self, addr):
+    self._num_streams += 1
+    logging.info('New Connection: %d' % self._num_streams)
+    if not _TEST_CASE_MAPPING.has_key(self._testcase):
+      logging.error('Unknown test case: %s' % self._testcase)
+      assert(0)
+    else:
+      t = _TEST_CASE_MAPPING[self._testcase]
+
+    if self._testcase == 'goaway':
+      return t(self._num_streams).get_base_server()
+    else:
+      return t().get_base_server()
+
+def parse_arguments():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--base_port', type=int, default=8080,
+    help='base port to run the servers (default: 8080). One test server is '
+    'started on each incrementing port, beginning with base_port, in the '
+    'following order: goaway,max_streams,ping,rst_after_data,rst_after_header,'
+    'rst_during_data'
+    )
+  return parser.parse_args()
+
+def start_test_servers(base_port):
+  """ Start one server per test case on incrementing port numbers
+  beginning with base_port """
+  index = 0
+  for test_case in sorted(_TEST_CASE_MAPPING.keys()):
+    portnum = base_port + index
+    logging.warning('serving on port %d : %s'%(portnum, test_case))
+    endpoint = twisted.internet.endpoints.TCP4ServerEndpoint(
+      twisted.internet.reactor, portnum, backlog=128)
+    endpoint.listen(H2Factory(test_case))
+    index += 1
+
+if __name__ == '__main__':
+  logging.basicConfig(
+    format='%(levelname) -10s %(asctime)s %(module)s:%(lineno)s | %(message)s',
+    level=logging.INFO)
+  args = parse_arguments()
+  start_test_servers(args.base_port)
+  twisted.internet.reactor.run()
diff --git a/test/http2_test/messages_pb2.py b/test/http2_test/messages_pb2.py
new file mode 100644
index 0000000..86cf5a8
--- /dev/null
+++ b/test/http2_test/messages_pb2.py
@@ -0,0 +1,661 @@
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: messages.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf.internal import enum_type_wrapper
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='messages.proto',
+  package='grpc.testing',
+  syntax='proto3',
+  serialized_pb=_b('\n\x0emessages.proto\x12\x0cgrpc.testing\"\x1a\n\tBoolValue\x12\r\n\x05value\x18\x01 \x01(\x08\"@\n\x07Payload\x12\'\n\x04type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x0c\n\x04\x62ody\x18\x02 \x01(\x0c\"+\n\nEchoStatus\x12\x0c\n\x04\x63ode\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\"\xce\x02\n\rSimpleRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12\x15\n\rresponse_size\x18\x02 \x01(\x05\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x15\n\rfill_username\x18\x04 \x01(\x08\x12\x18\n\x10\x66ill_oauth_scope\x18\x05 \x01(\x08\x12\x34\n\x13response_compressed\x18\x06 \x01(\x0b\x32\x17.grpc.testing.BoolValue\x12\x31\n\x0fresponse_status\x18\x07 \x01(\x0b\x32\x18.grpc.testing.EchoStatus\x12\x32\n\x11\x65xpect_compressed\x18\x08 \x01(\x0b\x32\x17.grpc.testing.BoolValue\"_\n\x0eSimpleResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x10\n\x08username\x18\x02 \x01(\t\x12\x13\n\x0boauth_scope\x18\x03 \x01(\t\"w\n\x19StreamingInputCallRequest\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x32\n\x11\x65xpect_compressed\x18\x02 \x01(\x0b\x32\x17.grpc.testing.BoolValue\"=\n\x1aStreamingInputCallResponse\x12\x1f\n\x17\x61ggregated_payload_size\x18\x01 \x01(\x05\"d\n\x12ResponseParameters\x12\x0c\n\x04size\x18\x01 \x01(\x05\x12\x13\n\x0binterval_us\x18\x02 \x01(\x05\x12+\n\ncompressed\x18\x03 \x01(\x0b\x32\x17.grpc.testing.BoolValue\"\xe8\x01\n\x1aStreamingOutputCallRequest\x12\x30\n\rresponse_type\x18\x01 \x01(\x0e\x32\x19.grpc.testing.PayloadType\x12=\n\x13response_parameters\x18\x02 \x03(\x0b\x32 .grpc.testing.ResponseParameters\x12&\n\x07payload\x18\x03 \x01(\x0b\x32\x15.grpc.testing.Payload\x12\x31\n\x0fresponse_status\x18\x07 \x01(\x0b\x32\x18.grpc.testing.EchoStatus\"E\n\x1bStreamingOutputCallResponse\x12&\n\x07payload\x18\x01 \x01(\x0b\x32\x15.grpc.testing.Payload\"3\n\x0fReconnectParams\x12 \n\x18max_reconnect_backoff_ms\x18\x01 \x01(\x05\"3\n\rReconnectInfo\x12\x0e\n\x06passed\x18\x01 \x01(\x08\x12\x12\n\nbackoff_ms\x18\x02 \x03(\x05*\x1f\n\x0bPayloadType\x12\x10\n\x0c\x43OMPRESSABLE\x10\x00\x62\x06proto3')
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+_PAYLOADTYPE = _descriptor.EnumDescriptor(
+  name='PayloadType',
+  full_name='grpc.testing.PayloadType',
+  filename=None,
+  file=DESCRIPTOR,
+  values=[
+    _descriptor.EnumValueDescriptor(
+      name='COMPRESSABLE', index=0, number=0,
+      options=None,
+      type=None),
+  ],
+  containing_type=None,
+  options=None,
+  serialized_start=1303,
+  serialized_end=1334,
+)
+_sym_db.RegisterEnumDescriptor(_PAYLOADTYPE)
+
+PayloadType = enum_type_wrapper.EnumTypeWrapper(_PAYLOADTYPE)
+COMPRESSABLE = 0
+
+
+
+_BOOLVALUE = _descriptor.Descriptor(
+  name='BoolValue',
+  full_name='grpc.testing.BoolValue',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='value', full_name='grpc.testing.BoolValue.value', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=32,
+  serialized_end=58,
+)
+
+
+_PAYLOAD = _descriptor.Descriptor(
+  name='Payload',
+  full_name='grpc.testing.Payload',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='type', full_name='grpc.testing.Payload.type', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='body', full_name='grpc.testing.Payload.body', index=1,
+      number=2, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b(""),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=60,
+  serialized_end=124,
+)
+
+
+_ECHOSTATUS = _descriptor.Descriptor(
+  name='EchoStatus',
+  full_name='grpc.testing.EchoStatus',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='code', full_name='grpc.testing.EchoStatus.code', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='message', full_name='grpc.testing.EchoStatus.message', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=126,
+  serialized_end=169,
+)
+
+
+_SIMPLEREQUEST = _descriptor.Descriptor(
+  name='SimpleRequest',
+  full_name='grpc.testing.SimpleRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='response_type', full_name='grpc.testing.SimpleRequest.response_type', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='response_size', full_name='grpc.testing.SimpleRequest.response_size', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='grpc.testing.SimpleRequest.payload', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='fill_username', full_name='grpc.testing.SimpleRequest.fill_username', index=3,
+      number=4, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='fill_oauth_scope', full_name='grpc.testing.SimpleRequest.fill_oauth_scope', index=4,
+      number=5, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='response_compressed', full_name='grpc.testing.SimpleRequest.response_compressed', index=5,
+      number=6, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='response_status', full_name='grpc.testing.SimpleRequest.response_status', index=6,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='expect_compressed', full_name='grpc.testing.SimpleRequest.expect_compressed', index=7,
+      number=8, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=172,
+  serialized_end=506,
+)
+
+
+_SIMPLERESPONSE = _descriptor.Descriptor(
+  name='SimpleResponse',
+  full_name='grpc.testing.SimpleResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='grpc.testing.SimpleResponse.payload', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='username', full_name='grpc.testing.SimpleResponse.username', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='oauth_scope', full_name='grpc.testing.SimpleResponse.oauth_scope', index=2,
+      number=3, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=_b("").decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=508,
+  serialized_end=603,
+)
+
+
+_STREAMINGINPUTCALLREQUEST = _descriptor.Descriptor(
+  name='StreamingInputCallRequest',
+  full_name='grpc.testing.StreamingInputCallRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='grpc.testing.StreamingInputCallRequest.payload', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='expect_compressed', full_name='grpc.testing.StreamingInputCallRequest.expect_compressed', index=1,
+      number=2, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=605,
+  serialized_end=724,
+)
+
+
+_STREAMINGINPUTCALLRESPONSE = _descriptor.Descriptor(
+  name='StreamingInputCallResponse',
+  full_name='grpc.testing.StreamingInputCallResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='aggregated_payload_size', full_name='grpc.testing.StreamingInputCallResponse.aggregated_payload_size', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=726,
+  serialized_end=787,
+)
+
+
+_RESPONSEPARAMETERS = _descriptor.Descriptor(
+  name='ResponseParameters',
+  full_name='grpc.testing.ResponseParameters',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='size', full_name='grpc.testing.ResponseParameters.size', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='interval_us', full_name='grpc.testing.ResponseParameters.interval_us', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='compressed', full_name='grpc.testing.ResponseParameters.compressed', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=789,
+  serialized_end=889,
+)
+
+
+_STREAMINGOUTPUTCALLREQUEST = _descriptor.Descriptor(
+  name='StreamingOutputCallRequest',
+  full_name='grpc.testing.StreamingOutputCallRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='response_type', full_name='grpc.testing.StreamingOutputCallRequest.response_type', index=0,
+      number=1, type=14, cpp_type=8, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='response_parameters', full_name='grpc.testing.StreamingOutputCallRequest.response_parameters', index=1,
+      number=2, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='grpc.testing.StreamingOutputCallRequest.payload', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='response_status', full_name='grpc.testing.StreamingOutputCallRequest.response_status', index=3,
+      number=7, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=892,
+  serialized_end=1124,
+)
+
+
+_STREAMINGOUTPUTCALLRESPONSE = _descriptor.Descriptor(
+  name='StreamingOutputCallResponse',
+  full_name='grpc.testing.StreamingOutputCallResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='payload', full_name='grpc.testing.StreamingOutputCallResponse.payload', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1126,
+  serialized_end=1195,
+)
+
+
+_RECONNECTPARAMS = _descriptor.Descriptor(
+  name='ReconnectParams',
+  full_name='grpc.testing.ReconnectParams',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='max_reconnect_backoff_ms', full_name='grpc.testing.ReconnectParams.max_reconnect_backoff_ms', index=0,
+      number=1, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1197,
+  serialized_end=1248,
+)
+
+
+_RECONNECTINFO = _descriptor.Descriptor(
+  name='ReconnectInfo',
+  full_name='grpc.testing.ReconnectInfo',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='passed', full_name='grpc.testing.ReconnectInfo.passed', index=0,
+      number=1, type=8, cpp_type=7, label=1,
+      has_default_value=False, default_value=False,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    _descriptor.FieldDescriptor(
+      name='backoff_ms', full_name='grpc.testing.ReconnectInfo.backoff_ms', index=1,
+      number=2, type=5, cpp_type=1, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=1250,
+  serialized_end=1301,
+)
+
+_PAYLOAD.fields_by_name['type'].enum_type = _PAYLOADTYPE
+_SIMPLEREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
+_SIMPLEREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_SIMPLEREQUEST.fields_by_name['response_compressed'].message_type = _BOOLVALUE
+_SIMPLEREQUEST.fields_by_name['response_status'].message_type = _ECHOSTATUS
+_SIMPLEREQUEST.fields_by_name['expect_compressed'].message_type = _BOOLVALUE
+_SIMPLERESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGINPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGINPUTCALLREQUEST.fields_by_name['expect_compressed'].message_type = _BOOLVALUE
+_RESPONSEPARAMETERS.fields_by_name['compressed'].message_type = _BOOLVALUE
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_type'].enum_type = _PAYLOADTYPE
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_parameters'].message_type = _RESPONSEPARAMETERS
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['payload'].message_type = _PAYLOAD
+_STREAMINGOUTPUTCALLREQUEST.fields_by_name['response_status'].message_type = _ECHOSTATUS
+_STREAMINGOUTPUTCALLRESPONSE.fields_by_name['payload'].message_type = _PAYLOAD
+DESCRIPTOR.message_types_by_name['BoolValue'] = _BOOLVALUE
+DESCRIPTOR.message_types_by_name['Payload'] = _PAYLOAD
+DESCRIPTOR.message_types_by_name['EchoStatus'] = _ECHOSTATUS
+DESCRIPTOR.message_types_by_name['SimpleRequest'] = _SIMPLEREQUEST
+DESCRIPTOR.message_types_by_name['SimpleResponse'] = _SIMPLERESPONSE
+DESCRIPTOR.message_types_by_name['StreamingInputCallRequest'] = _STREAMINGINPUTCALLREQUEST
+DESCRIPTOR.message_types_by_name['StreamingInputCallResponse'] = _STREAMINGINPUTCALLRESPONSE
+DESCRIPTOR.message_types_by_name['ResponseParameters'] = _RESPONSEPARAMETERS
+DESCRIPTOR.message_types_by_name['StreamingOutputCallRequest'] = _STREAMINGOUTPUTCALLREQUEST
+DESCRIPTOR.message_types_by_name['StreamingOutputCallResponse'] = _STREAMINGOUTPUTCALLRESPONSE
+DESCRIPTOR.message_types_by_name['ReconnectParams'] = _RECONNECTPARAMS
+DESCRIPTOR.message_types_by_name['ReconnectInfo'] = _RECONNECTINFO
+DESCRIPTOR.enum_types_by_name['PayloadType'] = _PAYLOADTYPE
+
+BoolValue = _reflection.GeneratedProtocolMessageType('BoolValue', (_message.Message,), dict(
+  DESCRIPTOR = _BOOLVALUE,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.BoolValue)
+  ))
+_sym_db.RegisterMessage(BoolValue)
+
+Payload = _reflection.GeneratedProtocolMessageType('Payload', (_message.Message,), dict(
+  DESCRIPTOR = _PAYLOAD,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.Payload)
+  ))
+_sym_db.RegisterMessage(Payload)
+
+EchoStatus = _reflection.GeneratedProtocolMessageType('EchoStatus', (_message.Message,), dict(
+  DESCRIPTOR = _ECHOSTATUS,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.EchoStatus)
+  ))
+_sym_db.RegisterMessage(EchoStatus)
+
+SimpleRequest = _reflection.GeneratedProtocolMessageType('SimpleRequest', (_message.Message,), dict(
+  DESCRIPTOR = _SIMPLEREQUEST,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.SimpleRequest)
+  ))
+_sym_db.RegisterMessage(SimpleRequest)
+
+SimpleResponse = _reflection.GeneratedProtocolMessageType('SimpleResponse', (_message.Message,), dict(
+  DESCRIPTOR = _SIMPLERESPONSE,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.SimpleResponse)
+  ))
+_sym_db.RegisterMessage(SimpleResponse)
+
+StreamingInputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingInputCallRequest', (_message.Message,), dict(
+  DESCRIPTOR = _STREAMINGINPUTCALLREQUEST,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallRequest)
+  ))
+_sym_db.RegisterMessage(StreamingInputCallRequest)
+
+StreamingInputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingInputCallResponse', (_message.Message,), dict(
+  DESCRIPTOR = _STREAMINGINPUTCALLRESPONSE,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingInputCallResponse)
+  ))
+_sym_db.RegisterMessage(StreamingInputCallResponse)
+
+ResponseParameters = _reflection.GeneratedProtocolMessageType('ResponseParameters', (_message.Message,), dict(
+  DESCRIPTOR = _RESPONSEPARAMETERS,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.ResponseParameters)
+  ))
+_sym_db.RegisterMessage(ResponseParameters)
+
+StreamingOutputCallRequest = _reflection.GeneratedProtocolMessageType('StreamingOutputCallRequest', (_message.Message,), dict(
+  DESCRIPTOR = _STREAMINGOUTPUTCALLREQUEST,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallRequest)
+  ))
+_sym_db.RegisterMessage(StreamingOutputCallRequest)
+
+StreamingOutputCallResponse = _reflection.GeneratedProtocolMessageType('StreamingOutputCallResponse', (_message.Message,), dict(
+  DESCRIPTOR = _STREAMINGOUTPUTCALLRESPONSE,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.StreamingOutputCallResponse)
+  ))
+_sym_db.RegisterMessage(StreamingOutputCallResponse)
+
+ReconnectParams = _reflection.GeneratedProtocolMessageType('ReconnectParams', (_message.Message,), dict(
+  DESCRIPTOR = _RECONNECTPARAMS,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.ReconnectParams)
+  ))
+_sym_db.RegisterMessage(ReconnectParams)
+
+ReconnectInfo = _reflection.GeneratedProtocolMessageType('ReconnectInfo', (_message.Message,), dict(
+  DESCRIPTOR = _RECONNECTINFO,
+  __module__ = 'messages_pb2'
+  # @@protoc_insertion_point(class_scope:grpc.testing.ReconnectInfo)
+  ))
+_sym_db.RegisterMessage(ReconnectInfo)
+
+
+# @@protoc_insertion_point(module_scope)
diff --git a/test/http2_test/test_goaway.py b/test/http2_test/test_goaway.py
new file mode 100644
index 0000000..61f4beb
--- /dev/null
+++ b/test/http2_test/test_goaway.py
@@ -0,0 +1,77 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+import time
+
+import http2_base_server
+
+class TestcaseGoaway(object):
+  """ 
+    This test does the following:
+      Process incoming request normally, i.e. send headers, data and trailers.
+      Then send a GOAWAY frame with the stream id of the processed request.
+      It checks that the next request is made on a different TCP connection.
+  """
+  def __init__(self, iteration):
+    self._base_server = http2_base_server.H2ProtocolBaseServer()
+    self._base_server._handlers['RequestReceived'] = self.on_request_received
+    self._base_server._handlers['DataReceived'] = self.on_data_received
+    self._base_server._handlers['SendDone'] = self.on_send_done
+    self._base_server._handlers['ConnectionLost'] = self.on_connection_lost
+    self._ready_to_send = False
+    self._iteration = iteration
+
+  def get_base_server(self):
+    return self._base_server
+
+  def on_connection_lost(self, reason):
+    logging.info('Disconnect received. Count %d' % self._iteration)
+    # _iteration == 2 => Two different connections have been used.
+    if self._iteration == 2:
+      self._base_server.on_connection_lost(reason)
+
+  def on_send_done(self, stream_id):
+    self._base_server.on_send_done_default(stream_id)
+    logging.info('Sending GOAWAY for stream %d:' % stream_id)
+    self._base_server._conn.close_connection(error_code=0, additional_data=None, last_stream_id=stream_id)
+    self._base_server._stream_status[stream_id] = False
+
+  def on_request_received(self, event):
+    self._ready_to_send = False
+    self._base_server.on_request_received_default(event)
+
+  def on_data_received(self, event):
+    self._base_server.on_data_received_default(event)
+    sr = self._base_server.parse_received_data(event.stream_id)
+    if sr:
+      logging.info('Creating response size = %s' % sr.response_size)
+      response_data = self._base_server.default_response_data(sr.response_size)
+      self._ready_to_send = True
+      self._base_server.setup_send(response_data, event.stream_id)
diff --git a/test/http2_test/test_max_streams.py b/test/http2_test/test_max_streams.py
new file mode 100644
index 0000000..9942b1b
--- /dev/null
+++ b/test/http2_test/test_max_streams.py
@@ -0,0 +1,63 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import hyperframe.frame
+import logging
+
+import http2_base_server
+
+class TestcaseSettingsMaxStreams(object):
+  """
+    This test sets MAX_CONCURRENT_STREAMS to 1 and asserts that at any point
+    only 1 stream is active.
+  """
+  def __init__(self):
+    self._base_server = http2_base_server.H2ProtocolBaseServer()
+    self._base_server._handlers['DataReceived'] = self.on_data_received
+    self._base_server._handlers['ConnectionMade'] = self.on_connection_made
+
+  def get_base_server(self):
+    return self._base_server
+
+  def on_connection_made(self):
+    logging.info('Connection Made')
+    self._base_server._conn.initiate_connection()
+    self._base_server._conn.update_settings(
+                  {hyperframe.frame.SettingsFrame.MAX_CONCURRENT_STREAMS: 1})
+    self._base_server.transport.setTcpNoDelay(True)
+    self._base_server.transport.write(self._base_server._conn.data_to_send())
+
+  def on_data_received(self, event):
+    self._base_server.on_data_received_default(event)
+    sr = self._base_server.parse_received_data(event.stream_id)
+    if sr:
+      logging.info('Creating response of size = %s' % sr.response_size)
+      response_data = self._base_server.default_response_data(sr.response_size)
+      self._base_server.setup_send(response_data, event.stream_id)
+    # TODO (makdharma): Add assertion to check number of live streams
diff --git a/test/http2_test/test_ping.py b/test/http2_test/test_ping.py
new file mode 100644
index 0000000..da41fd0
--- /dev/null
+++ b/test/http2_test/test_ping.py
@@ -0,0 +1,67 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import logging
+
+import http2_base_server
+
+class TestcasePing(object):
+  """
+    This test injects PING frames before and after header and data. Keeps count
+    of outstanding ping response and asserts when the count is non-zero at the
+    end of the test.
+  """
+  def __init__(self):
+    self._base_server = http2_base_server.H2ProtocolBaseServer()
+    self._base_server._handlers['RequestReceived'] = self.on_request_received
+    self._base_server._handlers['DataReceived'] = self.on_data_received
+    self._base_server._handlers['ConnectionLost'] = self.on_connection_lost
+
+  def get_base_server(self):
+    return self._base_server
+
+  def on_request_received(self, event):
+    self._base_server.default_ping()
+    self._base_server.on_request_received_default(event)
+    self._base_server.default_ping()
+
+  def on_data_received(self, event):
+    self._base_server.on_data_received_default(event)
+    sr = self._base_server.parse_received_data(event.stream_id)
+    if sr:
+      logging.info('Creating response size = %s' % sr.response_size)
+      response_data = self._base_server.default_response_data(sr.response_size)
+      self._base_server.default_ping()
+      self._base_server.setup_send(response_data, event.stream_id)
+      self._base_server.default_ping()
+
+  def on_connection_lost(self, reason):
+    logging.info('Disconnect received. Ping Count %d' % self._base_server._outstanding_pings)
+    assert(self._base_server._outstanding_pings == 0)
+    self._base_server.on_connection_lost(reason)
diff --git a/test/http2_test/test_rst_after_data.py b/test/http2_test/test_rst_after_data.py
new file mode 100644
index 0000000..9236025
--- /dev/null
+++ b/test/http2_test/test_rst_after_data.py
@@ -0,0 +1,57 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import http2_base_server
+
+class TestcaseRstStreamAfterData(object):
+  """
+    In response to an incoming request, this test sends headers, followed by
+    data, followed by a reset stream frame. Client asserts that the RPC failed.
+    Client needs to deliver the complete message to the application layer.
+  """
+  def __init__(self):
+    self._base_server = http2_base_server.H2ProtocolBaseServer()
+    self._base_server._handlers['DataReceived'] = self.on_data_received
+    self._base_server._handlers['SendDone'] = self.on_send_done
+
+  def get_base_server(self):
+    return self._base_server
+
+  def on_data_received(self, event):
+    self._base_server.on_data_received_default(event)
+    sr = self._base_server.parse_received_data(event.stream_id)
+    if sr:
+      response_data = self._base_server.default_response_data(sr.response_size)
+      self._ready_to_send = True
+      self._base_server.setup_send(response_data, event.stream_id)
+      # send reset stream
+
+  def on_send_done(self, stream_id):
+    self._base_server.send_reset_stream()
+    self._base_server._stream_status[stream_id] = False
diff --git a/tools/run_tests/build_artifact_csharp.sh b/test/http2_test/test_rst_after_header.py
old mode 100755
new mode 100644
similarity index 70%
copy from tools/run_tests/build_artifact_csharp.sh
copy to test/http2_test/test_rst_after_header.py
index 7438713..41e1adb
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/test/http2_test/test_rst_after_header.py
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,22 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+import http2_base_server
 
-cd $(dirname $0)/../..
+class TestcaseRstStreamAfterHeader(object):
+  """
+    In response to an incoming request, this test sends headers, followed by
+    a reset stream frame. Client asserts that the RPC failed.
+  """
+  def __init__(self):
+    self._base_server = http2_base_server.H2ProtocolBaseServer()
+    self._base_server._handlers['RequestReceived'] = self.on_request_received
 
-make grpc_csharp_ext
+  def get_base_server(self):
+    return self._base_server
 
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
+  def on_request_received(self, event):
+    # send initial headers
+    self._base_server.on_request_received_default(event)
+    # send reset stream
+    self._base_server.send_reset_stream()
diff --git a/test/http2_test/test_rst_during_data.py b/test/http2_test/test_rst_during_data.py
new file mode 100644
index 0000000..7c859db
--- /dev/null
+++ b/test/http2_test/test_rst_during_data.py
@@ -0,0 +1,58 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import http2_base_server
+
+class TestcaseRstStreamDuringData(object):
+  """
+    In response to an incoming request, this test sends headers, followed by
+    some data, followed by a reset stream frame. Client asserts that the RPC
+    failed and does not deliver the message to the application.
+  """
+  def __init__(self):
+    self._base_server = http2_base_server.H2ProtocolBaseServer()
+    self._base_server._handlers['DataReceived'] = self.on_data_received
+    self._base_server._handlers['SendDone'] = self.on_send_done
+
+  def get_base_server(self):
+    return self._base_server
+
+  def on_data_received(self, event):
+    self._base_server.on_data_received_default(event)
+    sr = self._base_server.parse_received_data(event.stream_id)
+    if sr:
+      response_data = self._base_server.default_response_data(sr.response_size)
+      self._ready_to_send = True
+      response_len = len(response_data)
+      truncated_response_data = response_data[0:response_len/2]
+      self._base_server.setup_send(truncated_response_data, event.stream_id)
+
+  def on_send_done(self, stream_id):
+    self._base_server.send_reset_stream()
+    self._base_server._stream_status[stream_id] = False
diff --git a/third_party/boringssl-with-bazel b/third_party/boringssl-with-bazel
new file mode 160000
index 0000000..886e7d7
--- /dev/null
+++ b/third_party/boringssl-with-bazel
@@ -0,0 +1 @@
+Subproject commit 886e7d75368e3f4fab3f4d0d3584e4abfc557755
diff --git a/third_party/zlib.BUILD b/third_party/zlib.BUILD
new file mode 100644
index 0000000..7879a81
--- /dev/null
+++ b/third_party/zlib.BUILD
@@ -0,0 +1,36 @@
+cc_library(
+    name = "z",
+    srcs = [
+        "adler32.c",
+        "compress.c",
+        "crc32.c",
+        "deflate.c",
+        "infback.c",
+        "inffast.c",
+        "inflate.c",
+        "inftrees.c",
+        "trees.c",
+        "uncompr.c",
+        "zutil.c",
+    ],
+    hdrs = [
+        "crc32.h",
+        "deflate.h",
+        "gzguts.h",
+        "inffast.h",
+        "inffixed.h",
+        "inflate.h",
+        "inftrees.h",
+        "trees.h",
+        "zconf.h",
+        "zlib.h",
+        "zutil.h",
+    ],
+    includes = [
+        "include",
+    ],
+    linkstatic = 1,
+    visibility = [
+        "//visibility:public",
+    ],
+)
diff --git a/tools/buildgen/generate_build_additions.sh b/tools/buildgen/generate_build_additions.sh
index 53c30c7..a4373ed 100644
--- a/tools/buildgen/generate_build_additions.sh
+++ b/tools/buildgen/generate_build_additions.sh
@@ -28,6 +28,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+set -e
+
 gen_build_yaml_dirs="  \
   src/boringssl        \
   src/benchmark \
diff --git a/tools/buildgen/generate_projects.py b/tools/buildgen/generate_projects.py
index 5e78ad5..f8ddaf4 100755
--- a/tools/buildgen/generate_projects.py
+++ b/tools/buildgen/generate_projects.py
@@ -36,7 +36,7 @@
 import sys
 import tempfile
 import multiprocessing
-sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..', 'run_tests'))
+sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..', 'run_tests', 'python_utils'))
 
 assert sys.argv[1:], 'run generate_projects.sh instead of this directly'
 
diff --git a/tools/codegen/core/gen_nano_proto.sh b/tools/codegen/core/gen_nano_proto.sh
index df107c2..99e4981 100755
--- a/tools/codegen/core/gen_nano_proto.sh
+++ b/tools/codegen/core/gen_nano_proto.sh
@@ -42,46 +42,6 @@
 # 4: Output dir not an absolute path.
 # 5: Couldn't create output directory (2nd argument).
 
-read -r -d '' COPYRIGHT <<'EOF'
-/*
- *
- * Copyright <YEAR>, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-EOF
-
-CURRENT_YEAR=$(date +%Y)
-COPYRIGHT_FILE=$(mktemp)
-echo "${COPYRIGHT/<YEAR>/$CURRENT_YEAR}" > $COPYRIGHT_FILE
-
 set -ex
 if [ $# -lt 2 ] || [ $# -gt 3 ]; then
   echo "Usage: $0 <input.proto> <absolute path to output dir> [grpc path]"
@@ -143,13 +103,6 @@
 sed -i "s:PB_${UC_PROTO_BASENAME}_PB_H_INCLUDED:GRPC_${INCLUDE_GUARD_BASE}_${UC_PROTO_BASENAME}_PB_H:g" \
   "$OUTPUT_DIR/$PROTO_BASENAME.pb.h"
 
-# prepend copyright
-TMPFILE=$(mktemp)
-cat $COPYRIGHT_FILE "$OUTPUT_DIR/$PROTO_BASENAME.pb.c" > $TMPFILE
-mv -v $TMPFILE "$OUTPUT_DIR/$PROTO_BASENAME.pb.c"
-cat $COPYRIGHT_FILE "$OUTPUT_DIR/$PROTO_BASENAME.pb.h" > $TMPFILE
-mv -v $TMPFILE "$OUTPUT_DIR/$PROTO_BASENAME.pb.h"
-
 deactivate
 rm -rf $VENV_DIR
 
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index f06e5f1..718bb56 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -92,9 +92,23 @@
   'LICENSE':    '',
 }
 
-KNOWN_BAD = set([
+_EXEMPT = frozenset((
+  # Generated protocol compiler output.
+  'examples/python/helloworld/helloworld_pb2.py',
+  'examples/python/helloworld/helloworld_pb2_grpc.py',
+  'examples/python/multiplex/helloworld_pb2.py',
+  'examples/python/multiplex/helloworld_pb2_grpc.py',
+  'examples/python/multiplex/route_guide_pb2.py',
+  'examples/python/multiplex/route_guide_pb2_grpc.py',
+  'examples/python/route_guide/route_guide_pb2.py',
+  'examples/python/route_guide/route_guide_pb2_grpc.py',
+
+  'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h',
+  'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+
+  # An older file originally from outside gRPC.
   'src/php/tests/bootstrap.php',
-])
+))
 
 
 RE_YEAR = r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+), Google Inc\.'
@@ -140,7 +154,8 @@
   sys.exit(0)
 
 for filename in filename_list:
-  if filename in KNOWN_BAD: continue
+  if filename in _EXEMPT:
+    continue
   ext = os.path.splitext(filename)[1]
   base = os.path.basename(filename)
   if ext in RE_LICENSE:
diff --git a/tools/distrib/check_nanopb_output.sh b/tools/distrib/check_nanopb_output.sh
index c070705..eb64e23 100755
--- a/tools/distrib/check_nanopb_output.sh
+++ b/tools/distrib/check_nanopb_output.sh
@@ -37,7 +37,7 @@
 pushd third_party/protobuf
 ./autogen.sh
 ./configure --prefix="$PROTOBUF_INSTALL_PREFIX"
-make
+make -j 8
 make install
 #ldconfig
 popd
@@ -51,7 +51,7 @@
 # stack up and change to nanopb's proto generator directory
 pushd third_party/nanopb/generator/proto
 export PATH="$PROTOC_BIN_PATH:$PATH"
-make
+make -j 8
 # back to the root directory
 popd
 
diff --git a/tools/distrib/clang_format_code.sh b/tools/distrib/clang_format_code.sh
index 858e074..13e0187 100755
--- a/tools/distrib/clang_format_code.sh
+++ b/tools/distrib/clang_format_code.sh
@@ -32,9 +32,15 @@
 
 # change to root directory
 cd $(dirname $0)/../..
+REPO_ROOT=$(pwd)
 
-# build clang-format docker image
-docker build -t grpc_clang_format tools/dockerfile/grpc_clang_format
+if [ "$CLANG_FORMAT_SKIP_DOCKER" == "" ]
+then
+  # build clang-format docker image
+  docker build -t grpc_clang_format tools/dockerfile/grpc_clang_format
 
-# run clang-format against the checked out codebase
-docker run -e TEST=$TEST -e CHANGED_FILES="$CHANGED_FILES" --rm=true -v ${HOST_GIT_ROOT:-`pwd`}:/local-code -t grpc_clang_format /clang_format_all_the_things.sh
+  # run clang-format against the checked out codebase
+  docker run -e TEST=$TEST -e CHANGED_FILES="$CHANGED_FILES" -e CLANG_FORMAT_ROOT="/local-code" --rm=true -v "${REPO_ROOT}":/local-code -t grpc_clang_format /clang_format_all_the_things.sh
+else
+  CLANG_FORMAT_ROOT="${REPO_ROOT}" tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+fi
diff --git a/tools/distrib/python/docgen.py b/tools/distrib/python/docgen.py
index 6223179..38ffcd6 100755
--- a/tools/distrib/python/docgen.py
+++ b/tools/distrib/python/docgen.py
@@ -94,6 +94,7 @@
   # specified repository, edit it, and push it. It's up to the user to then go
   # onto GitHub and make a PR against grpc/grpc:gh-pages.
   repo_parent_dir = tempfile.mkdtemp()
+  print('Documentation parent directory: {}'.format(repo_parent_dir))
   repo_dir = os.path.join(repo_parent_dir, 'grpc')
   python_doc_dir = os.path.join(repo_dir, 'python')
   doc_branch = args.doc_branch
diff --git a/tools/distrib/python/grpcio_tools/MANIFEST.in b/tools/distrib/python/grpcio_tools/MANIFEST.in
index 7712834..11ce367 100644
--- a/tools/distrib/python/grpcio_tools/MANIFEST.in
+++ b/tools/distrib/python/grpcio_tools/MANIFEST.in
@@ -2,6 +2,6 @@
 include protoc_deps.py
 include protoc_lib_deps.py
 include README.rst
-graft grpc
+graft grpc_tools
 graft grpc_root
 graft third_party
diff --git a/tools/distrib/python/grpcio_tools/grpc/__init__.py b/tools/distrib/python/grpcio_tools/grpc/__init__.py
deleted file mode 100644
index 70ac5ed..0000000
--- a/tools/distrib/python/grpcio_tools/grpc/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/tools/distrib/python/grpcio_tools/grpc/tools/__init__.py b/tools/distrib/python/grpcio_tools/grpc_tools/__init__.py
similarity index 100%
rename from tools/distrib/python/grpcio_tools/grpc/tools/__init__.py
rename to tools/distrib/python/grpcio_tools/grpc_tools/__init__.py
diff --git a/tools/distrib/python/grpcio_tools/grpc/tools/_protoc_compiler.pyx b/tools/distrib/python/grpcio_tools/grpc_tools/_protoc_compiler.pyx
similarity index 97%
rename from tools/distrib/python/grpcio_tools/grpc/tools/_protoc_compiler.pyx
rename to tools/distrib/python/grpcio_tools/grpc_tools/_protoc_compiler.pyx
index a653012..81034fa 100644
--- a/tools/distrib/python/grpcio_tools/grpc/tools/_protoc_compiler.pyx
+++ b/tools/distrib/python/grpcio_tools/grpc_tools/_protoc_compiler.pyx
@@ -29,7 +29,7 @@
 
 from libc cimport stdlib
 
-cdef extern from "grpc/tools/main.h":
+cdef extern from "grpc_tools/main.h":
   int protoc_main(int argc, char *argv[])
 
 def run_main(list args not None):
diff --git a/tools/distrib/python/grpcio_tools/grpc/tools/command.py b/tools/distrib/python/grpcio_tools/grpc_tools/command.py
similarity index 96%
rename from tools/distrib/python/grpcio_tools/grpc/tools/command.py
rename to tools/distrib/python/grpcio_tools/grpc_tools/command.py
index 424fd90..31b3331 100644
--- a/tools/distrib/python/grpcio_tools/grpc/tools/command.py
+++ b/tools/distrib/python/grpcio_tools/grpc_tools/command.py
@@ -33,7 +33,7 @@
 
 import setuptools
 
-from grpc.tools import protoc
+from grpc_tools import protoc
 
 
 def build_package_protos(package_root):
@@ -45,11 +45,11 @@
         proto_files.append(os.path.abspath(os.path.join(root, filename)))
 
   well_known_protos_include = pkg_resources.resource_filename(
-      'grpc.tools', '_proto')
+      'grpc_tools', '_proto')
 
   for proto_file in proto_files:
     command = [
-        'grpc.tools.protoc',
+        'grpc_tools.protoc',
         '--proto_path={}'.format(inclusion_root),
         '--proto_path={}'.format(well_known_protos_include),
         '--python_out={}'.format(inclusion_root),
diff --git a/tools/distrib/python/grpcio_tools/grpc/tools/main.cc b/tools/distrib/python/grpcio_tools/grpc_tools/main.cc
similarity index 98%
rename from tools/distrib/python/grpcio_tools/grpc/tools/main.cc
rename to tools/distrib/python/grpcio_tools/grpc_tools/main.cc
index 8391839..0c2fa31 100644
--- a/tools/distrib/python/grpcio_tools/grpc/tools/main.cc
+++ b/tools/distrib/python/grpcio_tools/grpc_tools/main.cc
@@ -32,7 +32,7 @@
 
 #include "src/compiler/python_generator.h"
 
-#include "grpc/tools/main.h"
+#include "grpc_tools/main.h"
 
 int protoc_main(int argc, char* argv[]) {
   google::protobuf::compiler::CommandLineInterface cli;
diff --git a/tools/distrib/python/grpcio_tools/grpc/tools/main.h b/tools/distrib/python/grpcio_tools/grpc_tools/main.h
similarity index 100%
rename from tools/distrib/python/grpcio_tools/grpc/tools/main.h
rename to tools/distrib/python/grpcio_tools/grpc_tools/main.h
diff --git a/tools/distrib/python/grpcio_tools/grpc/tools/protoc.py b/tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
similarity index 94%
rename from tools/distrib/python/grpcio_tools/grpc/tools/protoc.py
rename to tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
index e1256a7..63fddb2 100644
--- a/tools/distrib/python/grpcio_tools/grpc/tools/protoc.py
+++ b/tools/distrib/python/grpcio_tools/grpc_tools/protoc.py
@@ -32,7 +32,7 @@
 import pkg_resources
 import sys
 
-from grpc.tools import _protoc_compiler
+from grpc_tools import _protoc_compiler
 
 def main(command_arguments):
   """Run the protocol buffer compiler with the given command-line arguments.
@@ -45,5 +45,5 @@
   return _protoc_compiler.run_main(command_arguments)
 
 if __name__ == '__main__':
-  proto_include = pkg_resources.resource_filename('grpc.tools', '_proto')
+  proto_include = pkg_resources.resource_filename('grpc_tools', '_proto')
   sys.exit(main(sys.argv + ['-I{}'.format(proto_include)]))
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index a07a586..502d7ef 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -108,7 +108,7 @@
 CC_INCLUDE = os.path.normpath(protoc_lib_deps.CC_INCLUDE)
 PROTO_INCLUDE = os.path.normpath(protoc_lib_deps.PROTO_INCLUDE)
 
-GRPC_PYTHON_TOOLS_PACKAGE = 'grpc.tools'
+GRPC_PYTHON_TOOLS_PACKAGE = 'grpc_tools'
 GRPC_PYTHON_PROTO_RESOURCES_NAME = '_proto'
 
 DEFINE_MACROS = ()
@@ -154,16 +154,16 @@
 
 def extension_modules():
   if BUILD_WITH_CYTHON:
-    plugin_sources = [os.path.join('grpc', 'tools', '_protoc_compiler.pyx')]
+    plugin_sources = [os.path.join('grpc_tools', '_protoc_compiler.pyx')]
   else:
-    plugin_sources = [os.path.join('grpc', 'tools', '_protoc_compiler.cpp')]
+    plugin_sources = [os.path.join('grpc_tools', '_protoc_compiler.cpp')]
   plugin_sources += [
-    os.path.join('grpc', 'tools', 'main.cc'),
+    os.path.join('grpc_tools', 'main.cc'),
     os.path.join('grpc_root', 'src', 'compiler', 'python_generator.cc')] + [
     os.path.join(CC_INCLUDE, cc_file)
     for cc_file in CC_FILES]
   plugin_ext = extension.Extension(
-      name='grpc.tools._protoc_compiler',
+      name='grpc_tools._protoc_compiler',
       sources=plugin_sources,
       include_dirs=[
           '.',
@@ -184,12 +184,11 @@
     return extensions
 
 setuptools.setup(
-  name='grpcio_tools',
+  name='grpcio-tools',
   version=grpc_version.VERSION,
   license='3-clause BSD',
   ext_modules=extension_modules(),
   packages=setuptools.find_packages('.'),
-  namespace_packages=['grpc'],
   install_requires=[
     'protobuf>=3.0.0',
     'grpcio>={version}'.format(version=grpc_version.VERSION),
diff --git a/tools/dockerfile/grpc_artifact_protoc/Dockerfile b/tools/dockerfile/grpc_artifact_protoc/Dockerfile
index 1bbc6e0..2904a8f 100644
--- a/tools/dockerfile/grpc_artifact_protoc/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_protoc/Dockerfile
@@ -59,5 +59,11 @@
                    devtoolset-1.1-libstdc++-devel \
                    devtoolset-1.1-libstdc++-devel.i686 || true
 
+# Update Git to version >1.7 to allow cloning submodules with --reference arg.
+RUN yum remove -y git
+RUN yum install -y epel-release
+RUN yum install -y https://centos6.iuscommunity.org/ius-release.rpm
+RUN yum install -y git2u
+
 # Start in devtoolset environment that uses GCC 4.7
 CMD ["scl", "enable", "devtoolset-1.1", "bash"]
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
index 1d4e8e1..69e624a 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux_x64/Dockerfile
@@ -34,6 +34,19 @@
 # Update the package manager
 RUN yum update -y
 
+#############################################################
+# Update Git to allow cloning submodules with --reference arg
+RUN yum remove -y git
+RUN yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc
+RUN cd /usr/src && \
+  wget https://kernel.org/pub/software/scm/git/git-2.0.5.tar.gz && \
+  tar xzf git-2.0.5.tar.gz
+RUN cd /usr/src/git-2.0.5 && \
+  make prefix=/usr/local/git all && \
+  make prefix=/usr/local/git install
+ENV PATH /usr/local/git/bin:$PATH
+RUN source /etc/bashrc
+
 ###################################
 # Install Python build requirements
 RUN /opt/python/cp27-cp27m/bin/pip install cython
diff --git a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
index 8104996..9af8007 100644
--- a/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_python_manylinux_x86/Dockerfile
@@ -34,6 +34,19 @@
 # Update the package manager
 RUN yum update -y
 
+#############################################################
+# Update Git to allow cloning submodules with --reference arg
+RUN yum remove -y git
+RUN yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc
+RUN cd /usr/src && \
+  wget https://kernel.org/pub/software/scm/git/git-2.0.5.tar.gz && \
+  tar xzf git-2.0.5.tar.gz
+RUN cd /usr/src/git-2.0.5 && \
+  make prefix=/usr/local/git all && \
+  make prefix=/usr/local/git install
+ENV PATH /usr/local/git/bin:$PATH
+RUN source /etc/bashrc
+
 ###################################
 # Install Python build requirements
 RUN /opt/python/cp27-cp27m/bin/pip install cython
diff --git a/tools/dockerfile/grpc_clang_format/Dockerfile b/tools/dockerfile/grpc_clang_format/Dockerfile
index ab58017..85f5e4d 100644
--- a/tools/dockerfile/grpc_clang_format/Dockerfile
+++ b/tools/dockerfile/grpc_clang_format/Dockerfile
@@ -27,13 +27,13 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-FROM ubuntu:wily
-RUN apt-get update
-RUN apt-get -y install wget
+FROM ubuntu:15.10
+
+RUN apt-get update && apt-get -y install wget
 RUN echo deb http://llvm.org/apt/wily/ llvm-toolchain-wily-3.8 main >> /etc/apt/sources.list
 RUN echo deb-src http://llvm.org/apt/wily/ llvm-toolchain-wily-3.8 main >> /etc/apt/sources.list
 RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key| apt-key add -
-RUN apt-get update
-RUN apt-get -y install clang-format-3.8
+RUN apt-get update && apt-get -y install clang-format-3.8
+
 ADD clang_format_all_the_things.sh /
 CMD ["echo 'Run with tools/distrib/clang_format_code.sh'"]
diff --git a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
index 462c65a..c6e4aab 100755
--- a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+++ b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -44,7 +44,7 @@
 do
   for glob in $GLOB
   do
-    files="$files `find /local-code/$dir -name $glob -and -not -name *.generated.* -and -not -name *.pb.h -and -not -name *.pb.c -and -not -name *.pb.cc`"
+    files="$files `find ${CLANG_FORMAT_ROOT}/$dir -name $glob -and -not -name *.generated.* -and -not -name *.pb.h -and -not -name *.pb.c -and -not -name *.pb.cc`"
   done
 done
 
@@ -54,7 +54,7 @@
   files=$(comm -12 <(echo $files | tr ' ' '\n' | sort -u) <(echo $CHANGED_FILES | tr ' ' '\n' | sort -u))
 fi
 
-if [ "x$TEST" = "x" ]
+if [ "$TEST" == "" ]
 then
   echo $files | xargs $CLANG_FORMAT -i
 else
diff --git a/tools/run_tests/post_tests_csharp.sh b/tools/dockerfile/test/bazel/Dockerfile
old mode 100755
new mode 100644
similarity index 61%
copy from tools/run_tests/post_tests_csharp.sh
copy to tools/dockerfile/test/bazel/Dockerfile
index bb6f5c6..cc41384
--- a/tools/run_tests/post_tests_csharp.sh
+++ b/tools/dockerfile/test/bazel/Dockerfile
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -28,17 +27,52 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+FROM ubuntu:15.10
 
-if [ "$CONFIG" != "gcov" ] ; then exit ; fi
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
 
-# change to gRPC repo root
-cd $(dirname $0)/../..
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
 
-# Generate the csharp extension coverage report
-gcov objs/gcov/src/csharp/ext/*.o
-lcov --base-directory . --directory . -c -o coverage.info
-lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info
-genhtml -o reports/csharp_ext_coverage --num-spaces 2 \
-  -t 'gRPC C# native extension test coverage' coverage.info \
-  --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix
+
+#========================
+# Bazel installation
+RUN apt-get install -y software-properties-common g++
+RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
+RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
+RUN apt-get -y update
+RUN apt-get -y install bazel
+
+RUN mkdir -p /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index d9a7501..7f93933 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -63,6 +63,17 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+
+# Install Electron apt dependencies
+RUN apt-get update && apt-get install -y \
+  libasound2 \
+  libgconf-2-4 \
+  libgtk2.0-0 \
+  libnss3 \
+  libxss1 \
+  libxtst6 \
+  xvfb
+
 #====================
 # Python dependencies
 
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index 6b19ac8..811384f 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -97,17 +97,27 @@
 # ./compile.sh without a local protoc dependency
 # TODO(mattkwong): install dependencies to support latest Bazel version if newer
 # version is needed
-RUN git clone https://github.com/bazelbuild/bazel.git /bazel &&   cd /bazel && git checkout tags/0.4.1 && ./compile.sh
+RUN git clone https://github.com/bazelbuild/bazel.git /bazel && \
+  cd /bazel && git checkout tags/0.4.1 && ./compile.sh
 RUN ln -s /bazel/output/bazel /bin/
 
-#===================
-# Docker "inception"
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
+RUN apt-get update && apt-get -y install wget
+RUN echo deb http://llvm.org/apt/wily/ llvm-toolchain-wily-3.8 main >> /etc/apt/sources.list
+RUN echo deb-src http://llvm.org/apt/wily/ llvm-toolchain-wily-3.8 main >> /etc/apt/sources.list
+RUN wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key| apt-key add -
+RUN apt-get update && apt-get -y install clang-format-3.8
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
 
 RUN mkdir /var/local/jenkins
 
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index ff3a0e3..fa9b705 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -760,7 +760,35 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc++/alarm.h \
+INPUT                  = doc/PROTOCOL-HTTP2.md \
+doc/PROTOCOL-WEB.md \
+doc/binary-logging.md \
+doc/c-style-guide.md \
+doc/command_line_tool.md \
+doc/compression.md \
+doc/compression_cookbook.md \
+doc/connection-backoff-interop-test-description.md \
+doc/connection-backoff.md \
+doc/connectivity-semantics-and-api.md \
+doc/cpp-style-guide.md \
+doc/cpp/pending_api_cleanups.md \
+doc/cpp/perf_notes.md \
+doc/environment_variables.md \
+doc/epoll-polling-engine.md \
+doc/fail_fast.md \
+doc/g_stands_for.md \
+doc/health-checking.md \
+doc/http-grpc-status-mapping.md \
+doc/interop-test-descriptions.md \
+doc/load-balancing.md \
+doc/naming.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/server_reflection_tutorial.md \
+doc/statuscodes.md \
+doc/stress_test_framework.md \
+doc/wait-for-ready.md \
+include/grpc++/alarm.h \
 include/grpc++/channel.h \
 include/grpc++/client_context.h \
 include/grpc++/completion_queue.h \
@@ -771,7 +799,35 @@
 include/grpc++/grpc++.h \
 include/grpc++/impl/call.h \
 include/grpc++/impl/client_unary_call.h \
+include/grpc++/impl/codegen/async_stream.h \
+include/grpc++/impl/codegen/async_unary_call.h \
+include/grpc++/impl/codegen/call.h \
+include/grpc++/impl/codegen/call_hook.h \
+include/grpc++/impl/codegen/channel_interface.h \
+include/grpc++/impl/codegen/client_context.h \
+include/grpc++/impl/codegen/client_unary_call.h \
+include/grpc++/impl/codegen/completion_queue.h \
+include/grpc++/impl/codegen/completion_queue_tag.h \
+include/grpc++/impl/codegen/config.h \
 include/grpc++/impl/codegen/core_codegen.h \
+include/grpc++/impl/codegen/core_codegen_interface.h \
+include/grpc++/impl/codegen/create_auth_context.h \
+include/grpc++/impl/codegen/grpc_library.h \
+include/grpc++/impl/codegen/method_handler_impl.h \
+include/grpc++/impl/codegen/rpc_method.h \
+include/grpc++/impl/codegen/rpc_service_method.h \
+include/grpc++/impl/codegen/security/auth_context.h \
+include/grpc++/impl/codegen/serialization_traits.h \
+include/grpc++/impl/codegen/server_context.h \
+include/grpc++/impl/codegen/server_interface.h \
+include/grpc++/impl/codegen/service_type.h \
+include/grpc++/impl/codegen/status.h \
+include/grpc++/impl/codegen/status_code_enum.h \
+include/grpc++/impl/codegen/status_helper.h \
+include/grpc++/impl/codegen/string_ref.h \
+include/grpc++/impl/codegen/stub_options.h \
+include/grpc++/impl/codegen/sync_stream.h \
+include/grpc++/impl/codegen/time.h \
 include/grpc++/impl/grpc_library.h \
 include/grpc++/impl/method_handler_impl.h \
 include/grpc++/impl/rpc_method.h \
@@ -802,47 +858,20 @@
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
 include/grpc++/support/time.h \
-include/grpc++/impl/codegen/async_stream.h \
-include/grpc++/impl/codegen/async_unary_call.h \
-include/grpc++/impl/codegen/call.h \
-include/grpc++/impl/codegen/call_hook.h \
-include/grpc++/impl/codegen/channel_interface.h \
-include/grpc++/impl/codegen/client_context.h \
-include/grpc++/impl/codegen/client_unary_call.h \
-include/grpc++/impl/codegen/completion_queue.h \
-include/grpc++/impl/codegen/completion_queue_tag.h \
-include/grpc++/impl/codegen/config.h \
-include/grpc++/impl/codegen/core_codegen_interface.h \
-include/grpc++/impl/codegen/create_auth_context.h \
-include/grpc++/impl/codegen/grpc_library.h \
-include/grpc++/impl/codegen/method_handler_impl.h \
-include/grpc++/impl/codegen/rpc_method.h \
-include/grpc++/impl/codegen/rpc_service_method.h \
-include/grpc++/impl/codegen/security/auth_context.h \
-include/grpc++/impl/codegen/serialization_traits.h \
-include/grpc++/impl/codegen/server_context.h \
-include/grpc++/impl/codegen/server_interface.h \
-include/grpc++/impl/codegen/service_type.h \
-include/grpc++/impl/codegen/status.h \
-include/grpc++/impl/codegen/status_code_enum.h \
-include/grpc++/impl/codegen/status_helper.h \
-include/grpc++/impl/codegen/string_ref.h \
-include/grpc++/impl/codegen/stub_options.h \
-include/grpc++/impl/codegen/sync_stream.h \
-include/grpc++/impl/codegen/time.h \
-include/grpc/impl/codegen/byte_buffer_reader.h \
-include/grpc/impl/codegen/compression_types.h \
-include/grpc/impl/codegen/connectivity_state.h \
-include/grpc/impl/codegen/grpc_types.h \
-include/grpc/impl/codegen/propagation_bits.h \
-include/grpc/impl/codegen/status.h \
 include/grpc/impl/codegen/atm.h \
 include/grpc/impl/codegen/atm_gcc_atomic.h \
 include/grpc/impl/codegen/atm_gcc_sync.h \
 include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/exec_ctx_fwd.h \
 include/grpc/impl/codegen/gpr_types.h \
+include/grpc/impl/codegen/grpc_types.h \
 include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/propagation_bits.h \
 include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/status.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync_generic.h \
 include/grpc/impl/codegen/sync_posix.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 04e8f4e..bca5652a 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -760,7 +760,35 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc++/alarm.h \
+INPUT                  = doc/PROTOCOL-HTTP2.md \
+doc/PROTOCOL-WEB.md \
+doc/binary-logging.md \
+doc/c-style-guide.md \
+doc/command_line_tool.md \
+doc/compression.md \
+doc/compression_cookbook.md \
+doc/connection-backoff-interop-test-description.md \
+doc/connection-backoff.md \
+doc/connectivity-semantics-and-api.md \
+doc/cpp-style-guide.md \
+doc/cpp/pending_api_cleanups.md \
+doc/cpp/perf_notes.md \
+doc/environment_variables.md \
+doc/epoll-polling-engine.md \
+doc/fail_fast.md \
+doc/g_stands_for.md \
+doc/health-checking.md \
+doc/http-grpc-status-mapping.md \
+doc/interop-test-descriptions.md \
+doc/load-balancing.md \
+doc/naming.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/server_reflection_tutorial.md \
+doc/statuscodes.md \
+doc/stress_test_framework.md \
+doc/wait-for-ready.md \
+include/grpc++/alarm.h \
 include/grpc++/channel.h \
 include/grpc++/client_context.h \
 include/grpc++/completion_queue.h \
@@ -771,7 +799,36 @@
 include/grpc++/grpc++.h \
 include/grpc++/impl/call.h \
 include/grpc++/impl/client_unary_call.h \
+include/grpc++/impl/codegen/async_stream.h \
+include/grpc++/impl/codegen/async_unary_call.h \
+include/grpc++/impl/codegen/call.h \
+include/grpc++/impl/codegen/call_hook.h \
+include/grpc++/impl/codegen/channel_interface.h \
+include/grpc++/impl/codegen/client_context.h \
+include/grpc++/impl/codegen/client_unary_call.h \
+include/grpc++/impl/codegen/completion_queue.h \
+include/grpc++/impl/codegen/completion_queue_tag.h \
+include/grpc++/impl/codegen/config.h \
 include/grpc++/impl/codegen/core_codegen.h \
+include/grpc++/impl/codegen/core_codegen.h \
+include/grpc++/impl/codegen/core_codegen_interface.h \
+include/grpc++/impl/codegen/create_auth_context.h \
+include/grpc++/impl/codegen/grpc_library.h \
+include/grpc++/impl/codegen/method_handler_impl.h \
+include/grpc++/impl/codegen/rpc_method.h \
+include/grpc++/impl/codegen/rpc_service_method.h \
+include/grpc++/impl/codegen/security/auth_context.h \
+include/grpc++/impl/codegen/serialization_traits.h \
+include/grpc++/impl/codegen/server_context.h \
+include/grpc++/impl/codegen/server_interface.h \
+include/grpc++/impl/codegen/service_type.h \
+include/grpc++/impl/codegen/status.h \
+include/grpc++/impl/codegen/status_code_enum.h \
+include/grpc++/impl/codegen/status_helper.h \
+include/grpc++/impl/codegen/string_ref.h \
+include/grpc++/impl/codegen/stub_options.h \
+include/grpc++/impl/codegen/sync_stream.h \
+include/grpc++/impl/codegen/time.h \
 include/grpc++/impl/grpc_library.h \
 include/grpc++/impl/method_handler_impl.h \
 include/grpc++/impl/rpc_method.h \
@@ -802,97 +859,70 @@
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
 include/grpc++/support/time.h \
-include/grpc++/impl/codegen/async_stream.h \
-include/grpc++/impl/codegen/async_unary_call.h \
-include/grpc++/impl/codegen/call.h \
-include/grpc++/impl/codegen/call_hook.h \
-include/grpc++/impl/codegen/channel_interface.h \
-include/grpc++/impl/codegen/client_context.h \
-include/grpc++/impl/codegen/client_unary_call.h \
-include/grpc++/impl/codegen/completion_queue.h \
-include/grpc++/impl/codegen/completion_queue_tag.h \
-include/grpc++/impl/codegen/config.h \
-include/grpc++/impl/codegen/core_codegen_interface.h \
-include/grpc++/impl/codegen/create_auth_context.h \
-include/grpc++/impl/codegen/grpc_library.h \
-include/grpc++/impl/codegen/method_handler_impl.h \
-include/grpc++/impl/codegen/rpc_method.h \
-include/grpc++/impl/codegen/rpc_service_method.h \
-include/grpc++/impl/codegen/security/auth_context.h \
-include/grpc++/impl/codegen/serialization_traits.h \
-include/grpc++/impl/codegen/server_context.h \
-include/grpc++/impl/codegen/server_interface.h \
-include/grpc++/impl/codegen/service_type.h \
-include/grpc++/impl/codegen/status.h \
-include/grpc++/impl/codegen/status_code_enum.h \
-include/grpc++/impl/codegen/status_helper.h \
-include/grpc++/impl/codegen/string_ref.h \
-include/grpc++/impl/codegen/stub_options.h \
-include/grpc++/impl/codegen/sync_stream.h \
-include/grpc++/impl/codegen/time.h \
-include/grpc/impl/codegen/byte_buffer_reader.h \
-include/grpc/impl/codegen/compression_types.h \
-include/grpc/impl/codegen/connectivity_state.h \
-include/grpc/impl/codegen/grpc_types.h \
-include/grpc/impl/codegen/propagation_bits.h \
-include/grpc/impl/codegen/status.h \
 include/grpc/impl/codegen/atm.h \
 include/grpc/impl/codegen/atm_gcc_atomic.h \
 include/grpc/impl/codegen/atm_gcc_sync.h \
 include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/exec_ctx_fwd.h \
 include/grpc/impl/codegen/gpr_types.h \
+include/grpc/impl/codegen/grpc_types.h \
 include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/propagation_bits.h \
 include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/status.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync_generic.h \
 include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_windows.h \
-include/grpc++/impl/codegen/core_codegen.h \
-src/cpp/client/secure_credentials.h \
-src/cpp/common/secure_auth_context.h \
-src/cpp/server/secure_server_credentials.h \
-src/cpp/client/create_channel_internal.h \
-src/cpp/common/channel_filter.h \
-src/cpp/server/dynamic_thread_pool.h \
-src/cpp/server/thread_pool_interface.h \
-src/cpp/thread_manager/thread_manager.h \
-src/cpp/client/insecure_credentials.cc \
-src/cpp/client/secure_credentials.cc \
-src/cpp/common/auth_property_iterator.cc \
-src/cpp/common/secure_auth_context.cc \
-src/cpp/common/secure_channel_arguments.cc \
-src/cpp/common/secure_create_auth_context.cc \
-src/cpp/server/insecure_server_credentials.cc \
-src/cpp/server/secure_server_credentials.cc \
+src/cpp/README.md \
 src/cpp/client/channel_cc.cc \
 src/cpp/client/client_context.cc \
 src/cpp/client/create_channel.cc \
 src/cpp/client/create_channel_internal.cc \
+src/cpp/client/create_channel_internal.h \
 src/cpp/client/create_channel_posix.cc \
 src/cpp/client/credentials_cc.cc \
 src/cpp/client/generic_stub.cc \
+src/cpp/client/insecure_credentials.cc \
+src/cpp/client/secure_credentials.cc \
+src/cpp/client/secure_credentials.h \
+src/cpp/codegen/codegen_init.cc \
+src/cpp/common/auth_property_iterator.cc \
 src/cpp/common/channel_arguments.cc \
 src/cpp/common/channel_filter.cc \
+src/cpp/common/channel_filter.h \
 src/cpp/common/completion_queue_cc.cc \
 src/cpp/common/core_codegen.cc \
 src/cpp/common/resource_quota_cc.cc \
 src/cpp/common/rpc_method.cc \
+src/cpp/common/secure_auth_context.cc \
+src/cpp/common/secure_auth_context.h \
+src/cpp/common/secure_channel_arguments.cc \
+src/cpp/common/secure_create_auth_context.cc \
 src/cpp/common/version_cc.cc \
 src/cpp/server/async_generic_service.cc \
 src/cpp/server/create_default_thread_pool.cc \
 src/cpp/server/dynamic_thread_pool.cc \
+src/cpp/server/dynamic_thread_pool.h \
+src/cpp/server/insecure_server_credentials.cc \
+src/cpp/server/secure_server_credentials.cc \
+src/cpp/server/secure_server_credentials.h \
 src/cpp/server/server_builder.cc \
 src/cpp/server/server_cc.cc \
 src/cpp/server/server_context.cc \
 src/cpp/server/server_credentials.cc \
 src/cpp/server/server_posix.cc \
+src/cpp/server/thread_pool_interface.h \
 src/cpp/thread_manager/thread_manager.cc \
+src/cpp/thread_manager/thread_manager.h \
 src/cpp/util/byte_buffer_cc.cc \
 src/cpp/util/slice_cc.cc \
 src/cpp/util/status.cc \
 src/cpp/util/string_ref.cc \
-src/cpp/util/time_cc.cc \
-src/cpp/codegen/codegen_init.cc
+src/cpp/util/time_cc.cc
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index 1e748ba..ccbfe3a 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -760,34 +760,73 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/byte_buffer.h \
+INPUT                  = doc/PROTOCOL-HTTP2.md \
+doc/PROTOCOL-WEB.md \
+doc/binary-logging.md \
+doc/c-style-guide.md \
+doc/command_line_tool.md \
+doc/compression.md \
+doc/compression_cookbook.md \
+doc/connection-backoff-interop-test-description.md \
+doc/connection-backoff.md \
+doc/connectivity-semantics-and-api.md \
+doc/core/pending_api_cleanups.md \
+doc/cpp-style-guide.md \
+doc/environment_variables.md \
+doc/epoll-polling-engine.md \
+doc/fail_fast.md \
+doc/g_stands_for.md \
+doc/health-checking.md \
+doc/http-grpc-status-mapping.md \
+doc/interop-test-descriptions.md \
+doc/load-balancing.md \
+doc/naming.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/server_reflection_tutorial.md \
+doc/statuscodes.md \
+doc/stress_test_framework.md \
+doc/wait-for-ready.md \
+include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
+include/grpc/census.h \
 include/grpc/compression.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
+include/grpc/grpc_security.h \
 include/grpc/grpc_security_constants.h \
-include/grpc/slice.h \
-include/grpc/slice_buffer.h \
-include/grpc/status.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/atm_windows.h \
 include/grpc/impl/codegen/byte_buffer_reader.h \
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
-include/grpc/impl/codegen/grpc_types.h \
-include/grpc/impl/codegen/propagation_bits.h \
-include/grpc/impl/codegen/status.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/exec_ctx_fwd.h \
 include/grpc/impl/codegen/gpr_types.h \
+include/grpc/impl/codegen/gpr_types.h \
+include/grpc/impl/codegen/grpc_types.h \
 include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/propagation_bits.h \
 include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/status.h \
+include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_windows.h \
-include/grpc/grpc_security.h \
-include/grpc/census.h \
+include/grpc/impl/codegen/sync_windows.h \
+include/grpc/slice.h \
+include/grpc/slice_buffer.h \
+include/grpc/status.h \
 include/grpc/support/alloc.h \
 include/grpc/support/atm.h \
 include/grpc/support/atm_gcc_atomic.h \
@@ -813,18 +852,7 @@
 include/grpc/support/tls_gcc.h \
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_windows.h \
-include/grpc/impl/codegen/gpr_types.h \
-include/grpc/impl/codegen/port_platform.h \
-include/grpc/impl/codegen/slice.h \
-include/grpc/impl/codegen/sync.h \
-include/grpc/impl/codegen/sync_generic.h \
-include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_windows.h
+include/grpc/support/useful.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 6572bd4..fc8fac3 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -760,428 +760,73 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc/byte_buffer.h \
+INPUT                  = doc/PROTOCOL-HTTP2.md \
+doc/PROTOCOL-WEB.md \
+doc/binary-logging.md \
+doc/c-style-guide.md \
+doc/command_line_tool.md \
+doc/compression.md \
+doc/compression_cookbook.md \
+doc/connection-backoff-interop-test-description.md \
+doc/connection-backoff.md \
+doc/connectivity-semantics-and-api.md \
+doc/core/pending_api_cleanups.md \
+doc/cpp-style-guide.md \
+doc/environment_variables.md \
+doc/epoll-polling-engine.md \
+doc/fail_fast.md \
+doc/g_stands_for.md \
+doc/health-checking.md \
+doc/http-grpc-status-mapping.md \
+doc/interop-test-descriptions.md \
+doc/load-balancing.md \
+doc/naming.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/server_reflection_tutorial.md \
+doc/statuscodes.md \
+doc/stress_test_framework.md \
+doc/wait-for-ready.md \
+include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
+include/grpc/census.h \
 include/grpc/compression.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
+include/grpc/grpc_security.h \
 include/grpc/grpc_security_constants.h \
-include/grpc/slice.h \
-include/grpc/slice_buffer.h \
-include/grpc/status.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/atm_windows.h \
 include/grpc/impl/codegen/byte_buffer_reader.h \
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
-include/grpc/impl/codegen/grpc_types.h \
-include/grpc/impl/codegen/propagation_bits.h \
-include/grpc/impl/codegen/status.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/exec_ctx_fwd.h \
 include/grpc/impl/codegen/gpr_types.h \
+include/grpc/impl/codegen/gpr_types.h \
+include/grpc/impl/codegen/grpc_types.h \
 include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/propagation_bits.h \
 include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/status.h \
+include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_windows.h \
-include/grpc/grpc_security.h \
-include/grpc/census.h \
-src/core/lib/channel/channel_args.h \
-src/core/lib/channel/channel_stack.h \
-src/core/lib/channel/channel_stack_builder.h \
-src/core/lib/channel/compress_filter.h \
-src/core/lib/channel/connected_channel.h \
-src/core/lib/channel/context.h \
-src/core/lib/channel/deadline_filter.h \
-src/core/lib/channel/handshaker.h \
-src/core/lib/channel/http_client_filter.h \
-src/core/lib/channel/http_server_filter.h \
-src/core/lib/channel/message_size_filter.h \
-src/core/lib/compression/algorithm_metadata.h \
-src/core/lib/compression/message_compress.h \
-src/core/lib/debug/trace.h \
-src/core/lib/http/format_request.h \
-src/core/lib/http/httpcli.h \
-src/core/lib/http/parser.h \
-src/core/lib/iomgr/closure.h \
-src/core/lib/iomgr/combiner.h \
-src/core/lib/iomgr/endpoint.h \
-src/core/lib/iomgr/endpoint_pair.h \
-src/core/lib/iomgr/error.h \
-src/core/lib/iomgr/ev_epoll_linux.h \
-src/core/lib/iomgr/ev_poll_posix.h \
-src/core/lib/iomgr/ev_posix.h \
-src/core/lib/iomgr/exec_ctx.h \
-src/core/lib/iomgr/executor.h \
-src/core/lib/iomgr/iocp_windows.h \
-src/core/lib/iomgr/iomgr.h \
-src/core/lib/iomgr/iomgr_internal.h \
-src/core/lib/iomgr/iomgr_posix.h \
-src/core/lib/iomgr/load_file.h \
-src/core/lib/iomgr/network_status_tracker.h \
-src/core/lib/iomgr/polling_entity.h \
-src/core/lib/iomgr/pollset.h \
-src/core/lib/iomgr/pollset_set.h \
-src/core/lib/iomgr/pollset_set_windows.h \
-src/core/lib/iomgr/pollset_uv.h \
-src/core/lib/iomgr/pollset_windows.h \
-src/core/lib/iomgr/port.h \
-src/core/lib/iomgr/resolve_address.h \
-src/core/lib/iomgr/resource_quota.h \
-src/core/lib/iomgr/sockaddr.h \
-src/core/lib/iomgr/sockaddr_posix.h \
-src/core/lib/iomgr/sockaddr_utils.h \
-src/core/lib/iomgr/sockaddr_windows.h \
-src/core/lib/iomgr/socket_mutator.h \
-src/core/lib/iomgr/socket_utils.h \
-src/core/lib/iomgr/socket_utils_posix.h \
-src/core/lib/iomgr/socket_windows.h \
-src/core/lib/iomgr/tcp_client.h \
-src/core/lib/iomgr/tcp_client_posix.h \
-src/core/lib/iomgr/tcp_posix.h \
-src/core/lib/iomgr/tcp_server.h \
-src/core/lib/iomgr/tcp_uv.h \
-src/core/lib/iomgr/tcp_windows.h \
-src/core/lib/iomgr/time_averaged_stats.h \
-src/core/lib/iomgr/timer.h \
-src/core/lib/iomgr/timer_generic.h \
-src/core/lib/iomgr/timer_heap.h \
-src/core/lib/iomgr/timer_uv.h \
-src/core/lib/iomgr/udp_server.h \
-src/core/lib/iomgr/unix_sockets_posix.h \
-src/core/lib/iomgr/wakeup_fd_cv.h \
-src/core/lib/iomgr/wakeup_fd_pipe.h \
-src/core/lib/iomgr/wakeup_fd_posix.h \
-src/core/lib/iomgr/workqueue.h \
-src/core/lib/iomgr/workqueue_uv.h \
-src/core/lib/iomgr/workqueue_windows.h \
-src/core/lib/json/json.h \
-src/core/lib/json/json_common.h \
-src/core/lib/json/json_reader.h \
-src/core/lib/json/json_writer.h \
-src/core/lib/slice/percent_encoding.h \
-src/core/lib/slice/slice_string_helpers.h \
-src/core/lib/surface/api_trace.h \
-src/core/lib/surface/call.h \
-src/core/lib/surface/call_test_only.h \
-src/core/lib/surface/channel.h \
-src/core/lib/surface/channel_init.h \
-src/core/lib/surface/channel_stack_type.h \
-src/core/lib/surface/completion_queue.h \
-src/core/lib/surface/event_string.h \
-src/core/lib/surface/init.h \
-src/core/lib/surface/lame_client.h \
-src/core/lib/surface/server.h \
-src/core/lib/transport/byte_stream.h \
-src/core/lib/transport/connectivity_state.h \
-src/core/lib/transport/mdstr_hash_table.h \
-src/core/lib/transport/metadata.h \
-src/core/lib/transport/metadata_batch.h \
-src/core/lib/transport/pid_controller.h \
-src/core/lib/transport/service_config.h \
-src/core/lib/transport/static_metadata.h \
-src/core/lib/transport/timeout_encoding.h \
-src/core/lib/transport/transport.h \
-src/core/lib/transport/transport_impl.h \
-src/core/ext/transport/chttp2/transport/bin_decoder.h \
-src/core/ext/transport/chttp2/transport/bin_encoder.h \
-src/core/ext/transport/chttp2/transport/chttp2_transport.h \
-src/core/ext/transport/chttp2/transport/frame.h \
-src/core/ext/transport/chttp2/transport/frame_data.h \
-src/core/ext/transport/chttp2/transport/frame_goaway.h \
-src/core/ext/transport/chttp2/transport/frame_ping.h \
-src/core/ext/transport/chttp2/transport/frame_rst_stream.h \
-src/core/ext/transport/chttp2/transport/frame_settings.h \
-src/core/ext/transport/chttp2/transport/frame_window_update.h \
-src/core/ext/transport/chttp2/transport/hpack_encoder.h \
-src/core/ext/transport/chttp2/transport/hpack_parser.h \
-src/core/ext/transport/chttp2/transport/hpack_table.h \
-src/core/ext/transport/chttp2/transport/http2_errors.h \
-src/core/ext/transport/chttp2/transport/huffsyms.h \
-src/core/ext/transport/chttp2/transport/incoming_metadata.h \
-src/core/ext/transport/chttp2/transport/internal.h \
-src/core/ext/transport/chttp2/transport/status_conversion.h \
-src/core/ext/transport/chttp2/transport/stream_map.h \
-src/core/ext/transport/chttp2/transport/varint.h \
-src/core/ext/transport/chttp2/alpn/alpn.h \
-src/core/lib/security/context/security_context.h \
-src/core/lib/security/credentials/composite/composite_credentials.h \
-src/core/lib/security/credentials/credentials.h \
-src/core/lib/security/credentials/fake/fake_credentials.h \
-src/core/lib/security/credentials/google_default/google_default_credentials.h \
-src/core/lib/security/credentials/iam/iam_credentials.h \
-src/core/lib/security/credentials/jwt/json_token.h \
-src/core/lib/security/credentials/jwt/jwt_credentials.h \
-src/core/lib/security/credentials/jwt/jwt_verifier.h \
-src/core/lib/security/credentials/oauth2/oauth2_credentials.h \
-src/core/lib/security/credentials/plugin/plugin_credentials.h \
-src/core/lib/security/credentials/ssl/ssl_credentials.h \
-src/core/lib/security/transport/auth_filters.h \
-src/core/lib/security/transport/secure_endpoint.h \
-src/core/lib/security/transport/security_connector.h \
-src/core/lib/security/transport/security_handshaker.h \
-src/core/lib/security/transport/tsi_error.h \
-src/core/lib/security/util/b64.h \
-src/core/lib/security/util/json_util.h \
-src/core/lib/tsi/fake_transport_security.h \
-src/core/lib/tsi/ssl_transport_security.h \
-src/core/lib/tsi/ssl_types.h \
-src/core/lib/tsi/transport_security.h \
-src/core/lib/tsi/transport_security_interface.h \
-src/core/ext/transport/chttp2/server/chttp2_server.h \
-src/core/ext/client_channel/client_channel.h \
-src/core/ext/client_channel/client_channel_factory.h \
-src/core/ext/client_channel/connector.h \
-src/core/ext/client_channel/http_connect_handshaker.h \
-src/core/ext/client_channel/initial_connect_string.h \
-src/core/ext/client_channel/lb_policy.h \
-src/core/ext/client_channel/lb_policy_factory.h \
-src/core/ext/client_channel/lb_policy_registry.h \
-src/core/ext/client_channel/parse_address.h \
-src/core/ext/client_channel/resolver.h \
-src/core/ext/client_channel/resolver_factory.h \
-src/core/ext/client_channel/resolver_registry.h \
-src/core/ext/client_channel/subchannel.h \
-src/core/ext/client_channel/subchannel_index.h \
-src/core/ext/client_channel/uri_parser.h \
-src/core/ext/transport/chttp2/client/chttp2_connector.h \
-src/core/ext/lb_policy/grpclb/grpclb.h \
-src/core/ext/lb_policy/grpclb/load_balancer_api.h \
-src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \
-third_party/nanopb/pb.h \
-third_party/nanopb/pb_common.h \
-third_party/nanopb/pb_decode.h \
-third_party/nanopb/pb_encode.h \
-src/core/ext/load_reporting/load_reporting.h \
-src/core/ext/load_reporting/load_reporting_filter.h \
-src/core/ext/census/aggregation.h \
-src/core/ext/census/base_resources.h \
-src/core/ext/census/census_interface.h \
-src/core/ext/census/census_rpc_stats.h \
-src/core/ext/census/gen/census.pb.h \
-src/core/ext/census/gen/trace_context.pb.h \
-src/core/ext/census/grpc_filter.h \
-src/core/ext/census/mlog.h \
-src/core/ext/census/resource.h \
-src/core/ext/census/rpc_metric_id.h \
-src/core/ext/census/trace_context.h \
-src/core/lib/surface/init.c \
-src/core/lib/channel/channel_args.c \
-src/core/lib/channel/channel_stack.c \
-src/core/lib/channel/channel_stack_builder.c \
-src/core/lib/channel/compress_filter.c \
-src/core/lib/channel/connected_channel.c \
-src/core/lib/channel/deadline_filter.c \
-src/core/lib/channel/handshaker.c \
-src/core/lib/channel/http_client_filter.c \
-src/core/lib/channel/http_server_filter.c \
-src/core/lib/channel/message_size_filter.c \
-src/core/lib/compression/compression.c \
-src/core/lib/compression/message_compress.c \
-src/core/lib/debug/trace.c \
-src/core/lib/http/format_request.c \
-src/core/lib/http/httpcli.c \
-src/core/lib/http/parser.c \
-src/core/lib/iomgr/closure.c \
-src/core/lib/iomgr/combiner.c \
-src/core/lib/iomgr/endpoint.c \
-src/core/lib/iomgr/endpoint_pair_posix.c \
-src/core/lib/iomgr/endpoint_pair_uv.c \
-src/core/lib/iomgr/endpoint_pair_windows.c \
-src/core/lib/iomgr/error.c \
-src/core/lib/iomgr/ev_epoll_linux.c \
-src/core/lib/iomgr/ev_poll_posix.c \
-src/core/lib/iomgr/ev_posix.c \
-src/core/lib/iomgr/exec_ctx.c \
-src/core/lib/iomgr/executor.c \
-src/core/lib/iomgr/iocp_windows.c \
-src/core/lib/iomgr/iomgr.c \
-src/core/lib/iomgr/iomgr_posix.c \
-src/core/lib/iomgr/iomgr_uv.c \
-src/core/lib/iomgr/iomgr_windows.c \
-src/core/lib/iomgr/load_file.c \
-src/core/lib/iomgr/network_status_tracker.c \
-src/core/lib/iomgr/polling_entity.c \
-src/core/lib/iomgr/pollset_set_uv.c \
-src/core/lib/iomgr/pollset_set_windows.c \
-src/core/lib/iomgr/pollset_uv.c \
-src/core/lib/iomgr/pollset_windows.c \
-src/core/lib/iomgr/resolve_address_posix.c \
-src/core/lib/iomgr/resolve_address_uv.c \
-src/core/lib/iomgr/resolve_address_windows.c \
-src/core/lib/iomgr/resource_quota.c \
-src/core/lib/iomgr/sockaddr_utils.c \
-src/core/lib/iomgr/socket_mutator.c \
-src/core/lib/iomgr/socket_utils_common_posix.c \
-src/core/lib/iomgr/socket_utils_linux.c \
-src/core/lib/iomgr/socket_utils_posix.c \
-src/core/lib/iomgr/socket_utils_uv.c \
-src/core/lib/iomgr/socket_utils_windows.c \
-src/core/lib/iomgr/socket_windows.c \
-src/core/lib/iomgr/tcp_client_posix.c \
-src/core/lib/iomgr/tcp_client_uv.c \
-src/core/lib/iomgr/tcp_client_windows.c \
-src/core/lib/iomgr/tcp_posix.c \
-src/core/lib/iomgr/tcp_server_posix.c \
-src/core/lib/iomgr/tcp_server_uv.c \
-src/core/lib/iomgr/tcp_server_windows.c \
-src/core/lib/iomgr/tcp_uv.c \
-src/core/lib/iomgr/tcp_windows.c \
-src/core/lib/iomgr/time_averaged_stats.c \
-src/core/lib/iomgr/timer_generic.c \
-src/core/lib/iomgr/timer_heap.c \
-src/core/lib/iomgr/timer_uv.c \
-src/core/lib/iomgr/udp_server.c \
-src/core/lib/iomgr/unix_sockets_posix.c \
-src/core/lib/iomgr/unix_sockets_posix_noop.c \
-src/core/lib/iomgr/wakeup_fd_cv.c \
-src/core/lib/iomgr/wakeup_fd_eventfd.c \
-src/core/lib/iomgr/wakeup_fd_nospecial.c \
-src/core/lib/iomgr/wakeup_fd_pipe.c \
-src/core/lib/iomgr/wakeup_fd_posix.c \
-src/core/lib/iomgr/workqueue_uv.c \
-src/core/lib/iomgr/workqueue_windows.c \
-src/core/lib/json/json.c \
-src/core/lib/json/json_reader.c \
-src/core/lib/json/json_string.c \
-src/core/lib/json/json_writer.c \
-src/core/lib/slice/percent_encoding.c \
-src/core/lib/slice/slice.c \
-src/core/lib/slice/slice_buffer.c \
-src/core/lib/slice/slice_string_helpers.c \
-src/core/lib/surface/alarm.c \
-src/core/lib/surface/api_trace.c \
-src/core/lib/surface/byte_buffer.c \
-src/core/lib/surface/byte_buffer_reader.c \
-src/core/lib/surface/call.c \
-src/core/lib/surface/call_details.c \
-src/core/lib/surface/call_log_batch.c \
-src/core/lib/surface/channel.c \
-src/core/lib/surface/channel_init.c \
-src/core/lib/surface/channel_ping.c \
-src/core/lib/surface/channel_stack_type.c \
-src/core/lib/surface/completion_queue.c \
-src/core/lib/surface/event_string.c \
-src/core/lib/surface/lame_client.c \
-src/core/lib/surface/metadata_array.c \
-src/core/lib/surface/server.c \
-src/core/lib/surface/validate_metadata.c \
-src/core/lib/surface/version.c \
-src/core/lib/transport/byte_stream.c \
-src/core/lib/transport/connectivity_state.c \
-src/core/lib/transport/mdstr_hash_table.c \
-src/core/lib/transport/metadata.c \
-src/core/lib/transport/metadata_batch.c \
-src/core/lib/transport/pid_controller.c \
-src/core/lib/transport/service_config.c \
-src/core/lib/transport/static_metadata.c \
-src/core/lib/transport/timeout_encoding.c \
-src/core/lib/transport/transport.c \
-src/core/lib/transport/transport_op_string.c \
-src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
-src/core/ext/transport/chttp2/transport/bin_decoder.c \
-src/core/ext/transport/chttp2/transport/bin_encoder.c \
-src/core/ext/transport/chttp2/transport/chttp2_plugin.c \
-src/core/ext/transport/chttp2/transport/chttp2_transport.c \
-src/core/ext/transport/chttp2/transport/frame_data.c \
-src/core/ext/transport/chttp2/transport/frame_goaway.c \
-src/core/ext/transport/chttp2/transport/frame_ping.c \
-src/core/ext/transport/chttp2/transport/frame_rst_stream.c \
-src/core/ext/transport/chttp2/transport/frame_settings.c \
-src/core/ext/transport/chttp2/transport/frame_window_update.c \
-src/core/ext/transport/chttp2/transport/hpack_encoder.c \
-src/core/ext/transport/chttp2/transport/hpack_parser.c \
-src/core/ext/transport/chttp2/transport/hpack_table.c \
-src/core/ext/transport/chttp2/transport/huffsyms.c \
-src/core/ext/transport/chttp2/transport/incoming_metadata.c \
-src/core/ext/transport/chttp2/transport/parsing.c \
-src/core/ext/transport/chttp2/transport/status_conversion.c \
-src/core/ext/transport/chttp2/transport/stream_lists.c \
-src/core/ext/transport/chttp2/transport/stream_map.c \
-src/core/ext/transport/chttp2/transport/varint.c \
-src/core/ext/transport/chttp2/transport/writing.c \
-src/core/ext/transport/chttp2/alpn/alpn.c \
-src/core/lib/http/httpcli_security_connector.c \
-src/core/lib/security/context/security_context.c \
-src/core/lib/security/credentials/composite/composite_credentials.c \
-src/core/lib/security/credentials/credentials.c \
-src/core/lib/security/credentials/credentials_metadata.c \
-src/core/lib/security/credentials/fake/fake_credentials.c \
-src/core/lib/security/credentials/google_default/credentials_generic.c \
-src/core/lib/security/credentials/google_default/google_default_credentials.c \
-src/core/lib/security/credentials/iam/iam_credentials.c \
-src/core/lib/security/credentials/jwt/json_token.c \
-src/core/lib/security/credentials/jwt/jwt_credentials.c \
-src/core/lib/security/credentials/jwt/jwt_verifier.c \
-src/core/lib/security/credentials/oauth2/oauth2_credentials.c \
-src/core/lib/security/credentials/plugin/plugin_credentials.c \
-src/core/lib/security/credentials/ssl/ssl_credentials.c \
-src/core/lib/security/transport/client_auth_filter.c \
-src/core/lib/security/transport/secure_endpoint.c \
-src/core/lib/security/transport/security_connector.c \
-src/core/lib/security/transport/security_handshaker.c \
-src/core/lib/security/transport/server_auth_filter.c \
-src/core/lib/security/transport/tsi_error.c \
-src/core/lib/security/util/b64.c \
-src/core/lib/security/util/json_util.c \
-src/core/lib/surface/init_secure.c \
-src/core/lib/tsi/fake_transport_security.c \
-src/core/lib/tsi/ssl_transport_security.c \
-src/core/lib/tsi/transport_security.c \
-src/core/ext/transport/chttp2/server/chttp2_server.c \
-src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
-src/core/ext/client_channel/channel_connectivity.c \
-src/core/ext/client_channel/client_channel.c \
-src/core/ext/client_channel/client_channel_factory.c \
-src/core/ext/client_channel/client_channel_plugin.c \
-src/core/ext/client_channel/connector.c \
-src/core/ext/client_channel/default_initial_connect_string.c \
-src/core/ext/client_channel/http_connect_handshaker.c \
-src/core/ext/client_channel/initial_connect_string.c \
-src/core/ext/client_channel/lb_policy.c \
-src/core/ext/client_channel/lb_policy_factory.c \
-src/core/ext/client_channel/lb_policy_registry.c \
-src/core/ext/client_channel/parse_address.c \
-src/core/ext/client_channel/resolver.c \
-src/core/ext/client_channel/resolver_factory.c \
-src/core/ext/client_channel/resolver_registry.c \
-src/core/ext/client_channel/subchannel.c \
-src/core/ext/client_channel/subchannel_index.c \
-src/core/ext/client_channel/uri_parser.c \
-src/core/ext/transport/chttp2/client/chttp2_connector.c \
-src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
-src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
-src/core/ext/transport/chttp2/client/insecure/channel_create.c \
-src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
-src/core/ext/lb_policy/grpclb/grpclb.c \
-src/core/ext/lb_policy/grpclb/load_balancer_api.c \
-src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
-third_party/nanopb/pb_common.c \
-third_party/nanopb/pb_decode.c \
-third_party/nanopb/pb_encode.c \
-src/core/ext/lb_policy/pick_first/pick_first.c \
-src/core/ext/lb_policy/round_robin/round_robin.c \
-src/core/ext/resolver/dns/native/dns_resolver.c \
-src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
-src/core/ext/load_reporting/load_reporting.c \
-src/core/ext/load_reporting/load_reporting_filter.c \
-src/core/ext/census/base_resources.c \
-src/core/ext/census/context.c \
-src/core/ext/census/gen/census.pb.c \
-src/core/ext/census/gen/trace_context.pb.c \
-src/core/ext/census/grpc_context.c \
-src/core/ext/census/grpc_filter.c \
-src/core/ext/census/grpc_plugin.c \
-src/core/ext/census/initialize.c \
-src/core/ext/census/mlog.c \
-src/core/ext/census/operation.c \
-src/core/ext/census/placeholders.c \
-src/core/ext/census/resource.c \
-src/core/ext/census/trace_context.c \
-src/core/ext/census/tracing.c \
-src/core/plugin_registry/grpc_plugin_registry.c \
+include/grpc/impl/codegen/sync_windows.h \
+include/grpc/slice.h \
+include/grpc/slice_buffer.h \
+include/grpc/status.h \
 include/grpc/support/alloc.h \
 include/grpc/support/atm.h \
 include/grpc/support/atm_gcc_atomic.h \
@@ -1208,39 +853,368 @@
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
 include/grpc/support/useful.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_windows.h \
-include/grpc/impl/codegen/gpr_types.h \
-include/grpc/impl/codegen/port_platform.h \
-include/grpc/impl/codegen/slice.h \
-include/grpc/impl/codegen/sync.h \
-include/grpc/impl/codegen/sync_generic.h \
-include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_windows.h \
-src/core/lib/profiling/timers.h \
-src/core/lib/support/backoff.h \
-src/core/lib/support/block_annotate.h \
-src/core/lib/support/env.h \
-src/core/lib/support/mpscq.h \
-src/core/lib/support/murmur_hash.h \
-src/core/lib/support/stack_lockfree.h \
-src/core/lib/support/string.h \
-src/core/lib/support/string_windows.h \
-src/core/lib/support/thd_internal.h \
-src/core/lib/support/time_precise.h \
-src/core/lib/support/tmpfile.h \
+src/core/README.md \
+src/core/ext/README.md \
+src/core/ext/census/README.md \
+src/core/ext/census/aggregation.h \
+src/core/ext/census/base_resources.c \
+src/core/ext/census/base_resources.h \
+src/core/ext/census/census_interface.h \
+src/core/ext/census/census_rpc_stats.h \
+src/core/ext/census/context.c \
+src/core/ext/census/gen/README.md \
+src/core/ext/census/gen/census.pb.c \
+src/core/ext/census/gen/census.pb.h \
+src/core/ext/census/gen/trace_context.pb.c \
+src/core/ext/census/gen/trace_context.pb.h \
+src/core/ext/census/grpc_context.c \
+src/core/ext/census/grpc_filter.c \
+src/core/ext/census/grpc_filter.h \
+src/core/ext/census/grpc_plugin.c \
+src/core/ext/census/initialize.c \
+src/core/ext/census/mlog.c \
+src/core/ext/census/mlog.h \
+src/core/ext/census/operation.c \
+src/core/ext/census/placeholders.c \
+src/core/ext/census/resource.c \
+src/core/ext/census/resource.h \
+src/core/ext/census/rpc_metric_id.h \
+src/core/ext/census/trace_context.c \
+src/core/ext/census/trace_context.h \
+src/core/ext/census/tracing.c \
+src/core/ext/client_channel/README.md \
+src/core/ext/client_channel/channel_connectivity.c \
+src/core/ext/client_channel/client_channel.c \
+src/core/ext/client_channel/client_channel.h \
+src/core/ext/client_channel/client_channel_factory.c \
+src/core/ext/client_channel/client_channel_factory.h \
+src/core/ext/client_channel/client_channel_plugin.c \
+src/core/ext/client_channel/connector.c \
+src/core/ext/client_channel/connector.h \
+src/core/ext/client_channel/default_initial_connect_string.c \
+src/core/ext/client_channel/http_connect_handshaker.c \
+src/core/ext/client_channel/http_connect_handshaker.h \
+src/core/ext/client_channel/initial_connect_string.c \
+src/core/ext/client_channel/initial_connect_string.h \
+src/core/ext/client_channel/lb_policy.c \
+src/core/ext/client_channel/lb_policy.h \
+src/core/ext/client_channel/lb_policy_factory.c \
+src/core/ext/client_channel/lb_policy_factory.h \
+src/core/ext/client_channel/lb_policy_registry.c \
+src/core/ext/client_channel/lb_policy_registry.h \
+src/core/ext/client_channel/parse_address.c \
+src/core/ext/client_channel/parse_address.h \
+src/core/ext/client_channel/resolver.c \
+src/core/ext/client_channel/resolver.h \
+src/core/ext/client_channel/resolver_factory.c \
+src/core/ext/client_channel/resolver_factory.h \
+src/core/ext/client_channel/resolver_registry.c \
+src/core/ext/client_channel/resolver_registry.h \
+src/core/ext/client_channel/subchannel.c \
+src/core/ext/client_channel/subchannel.h \
+src/core/ext/client_channel/subchannel_index.c \
+src/core/ext/client_channel/subchannel_index.h \
+src/core/ext/client_channel/uri_parser.c \
+src/core/ext/client_channel/uri_parser.h \
+src/core/ext/lb_policy/grpclb/grpclb.c \
+src/core/ext/lb_policy/grpclb/grpclb.h \
+src/core/ext/lb_policy/grpclb/load_balancer_api.c \
+src/core/ext/lb_policy/grpclb/load_balancer_api.h \
+src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \
+src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \
+src/core/ext/lb_policy/pick_first/pick_first.c \
+src/core/ext/lb_policy/round_robin/round_robin.c \
+src/core/ext/load_reporting/load_reporting.c \
+src/core/ext/load_reporting/load_reporting.h \
+src/core/ext/load_reporting/load_reporting_filter.c \
+src/core/ext/load_reporting/load_reporting_filter.h \
+src/core/ext/resolver/README.md \
+src/core/ext/resolver/dns/native/README.md \
+src/core/ext/resolver/dns/native/dns_resolver.c \
+src/core/ext/resolver/sockaddr/README.md \
+src/core/ext/resolver/sockaddr/sockaddr_resolver.c \
+src/core/ext/transport/README.md \
+src/core/ext/transport/chttp2/README.md \
+src/core/ext/transport/chttp2/alpn/alpn.c \
+src/core/ext/transport/chttp2/alpn/alpn.h \
+src/core/ext/transport/chttp2/client/chttp2_connector.c \
+src/core/ext/transport/chttp2/client/chttp2_connector.h \
+src/core/ext/transport/chttp2/client/insecure/README.md \
+src/core/ext/transport/chttp2/client/insecure/channel_create.c \
+src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
+src/core/ext/transport/chttp2/client/secure/README.md \
+src/core/ext/transport/chttp2/client/secure/secure_channel_create.c \
+src/core/ext/transport/chttp2/server/chttp2_server.c \
+src/core/ext/transport/chttp2/server/chttp2_server.h \
+src/core/ext/transport/chttp2/server/insecure/README.md \
+src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
+src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
+src/core/ext/transport/chttp2/server/secure/README.md \
+src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c \
+src/core/ext/transport/chttp2/transport/README.md \
+src/core/ext/transport/chttp2/transport/bin_decoder.c \
+src/core/ext/transport/chttp2/transport/bin_decoder.h \
+src/core/ext/transport/chttp2/transport/bin_encoder.c \
+src/core/ext/transport/chttp2/transport/bin_encoder.h \
+src/core/ext/transport/chttp2/transport/chttp2_plugin.c \
+src/core/ext/transport/chttp2/transport/chttp2_transport.c \
+src/core/ext/transport/chttp2/transport/chttp2_transport.h \
+src/core/ext/transport/chttp2/transport/frame.h \
+src/core/ext/transport/chttp2/transport/frame_data.c \
+src/core/ext/transport/chttp2/transport/frame_data.h \
+src/core/ext/transport/chttp2/transport/frame_goaway.c \
+src/core/ext/transport/chttp2/transport/frame_goaway.h \
+src/core/ext/transport/chttp2/transport/frame_ping.c \
+src/core/ext/transport/chttp2/transport/frame_ping.h \
+src/core/ext/transport/chttp2/transport/frame_rst_stream.c \
+src/core/ext/transport/chttp2/transport/frame_rst_stream.h \
+src/core/ext/transport/chttp2/transport/frame_settings.c \
+src/core/ext/transport/chttp2/transport/frame_settings.h \
+src/core/ext/transport/chttp2/transport/frame_window_update.c \
+src/core/ext/transport/chttp2/transport/frame_window_update.h \
+src/core/ext/transport/chttp2/transport/hpack_encoder.c \
+src/core/ext/transport/chttp2/transport/hpack_encoder.h \
+src/core/ext/transport/chttp2/transport/hpack_parser.c \
+src/core/ext/transport/chttp2/transport/hpack_parser.h \
+src/core/ext/transport/chttp2/transport/hpack_table.c \
+src/core/ext/transport/chttp2/transport/hpack_table.h \
+src/core/ext/transport/chttp2/transport/http2_errors.h \
+src/core/ext/transport/chttp2/transport/huffsyms.c \
+src/core/ext/transport/chttp2/transport/huffsyms.h \
+src/core/ext/transport/chttp2/transport/incoming_metadata.c \
+src/core/ext/transport/chttp2/transport/incoming_metadata.h \
+src/core/ext/transport/chttp2/transport/internal.h \
+src/core/ext/transport/chttp2/transport/parsing.c \
+src/core/ext/transport/chttp2/transport/status_conversion.c \
+src/core/ext/transport/chttp2/transport/status_conversion.h \
+src/core/ext/transport/chttp2/transport/stream_lists.c \
+src/core/ext/transport/chttp2/transport/stream_map.c \
+src/core/ext/transport/chttp2/transport/stream_map.h \
+src/core/ext/transport/chttp2/transport/varint.c \
+src/core/ext/transport/chttp2/transport/varint.h \
+src/core/ext/transport/chttp2/transport/writing.c \
+src/core/lib/README.md \
+src/core/lib/channel/README.md \
+src/core/lib/channel/channel_args.c \
+src/core/lib/channel/channel_args.h \
+src/core/lib/channel/channel_stack.c \
+src/core/lib/channel/channel_stack.h \
+src/core/lib/channel/channel_stack_builder.c \
+src/core/lib/channel/channel_stack_builder.h \
+src/core/lib/channel/compress_filter.c \
+src/core/lib/channel/compress_filter.h \
+src/core/lib/channel/connected_channel.c \
+src/core/lib/channel/connected_channel.h \
+src/core/lib/channel/context.h \
+src/core/lib/channel/deadline_filter.c \
+src/core/lib/channel/deadline_filter.h \
+src/core/lib/channel/handshaker.c \
+src/core/lib/channel/handshaker.h \
+src/core/lib/channel/handshaker_factory.c \
+src/core/lib/channel/handshaker_factory.h \
+src/core/lib/channel/handshaker_registry.c \
+src/core/lib/channel/handshaker_registry.h \
+src/core/lib/channel/http_client_filter.c \
+src/core/lib/channel/http_client_filter.h \
+src/core/lib/channel/http_server_filter.c \
+src/core/lib/channel/http_server_filter.h \
+src/core/lib/channel/message_size_filter.c \
+src/core/lib/channel/message_size_filter.h \
+src/core/lib/compression/algorithm_metadata.h \
+src/core/lib/compression/compression.c \
+src/core/lib/compression/message_compress.c \
+src/core/lib/compression/message_compress.h \
+src/core/lib/debug/trace.c \
+src/core/lib/debug/trace.h \
+src/core/lib/http/format_request.c \
+src/core/lib/http/format_request.h \
+src/core/lib/http/httpcli.c \
+src/core/lib/http/httpcli.h \
+src/core/lib/http/httpcli_security_connector.c \
+src/core/lib/http/parser.c \
+src/core/lib/http/parser.h \
+src/core/lib/iomgr/README.md \
+src/core/lib/iomgr/closure.c \
+src/core/lib/iomgr/closure.h \
+src/core/lib/iomgr/combiner.c \
+src/core/lib/iomgr/combiner.h \
+src/core/lib/iomgr/endpoint.c \
+src/core/lib/iomgr/endpoint.h \
+src/core/lib/iomgr/endpoint_pair.h \
+src/core/lib/iomgr/endpoint_pair_posix.c \
+src/core/lib/iomgr/endpoint_pair_uv.c \
+src/core/lib/iomgr/endpoint_pair_windows.c \
+src/core/lib/iomgr/error.c \
+src/core/lib/iomgr/error.h \
+src/core/lib/iomgr/ev_epoll_linux.c \
+src/core/lib/iomgr/ev_epoll_linux.h \
+src/core/lib/iomgr/ev_poll_posix.c \
+src/core/lib/iomgr/ev_poll_posix.h \
+src/core/lib/iomgr/ev_posix.c \
+src/core/lib/iomgr/ev_posix.h \
+src/core/lib/iomgr/exec_ctx.c \
+src/core/lib/iomgr/exec_ctx.h \
+src/core/lib/iomgr/executor.c \
+src/core/lib/iomgr/executor.h \
+src/core/lib/iomgr/iocp_windows.c \
+src/core/lib/iomgr/iocp_windows.h \
+src/core/lib/iomgr/iomgr.c \
+src/core/lib/iomgr/iomgr.h \
+src/core/lib/iomgr/iomgr_internal.h \
+src/core/lib/iomgr/iomgr_posix.c \
+src/core/lib/iomgr/iomgr_posix.h \
+src/core/lib/iomgr/iomgr_uv.c \
+src/core/lib/iomgr/iomgr_windows.c \
+src/core/lib/iomgr/load_file.c \
+src/core/lib/iomgr/load_file.h \
+src/core/lib/iomgr/network_status_tracker.c \
+src/core/lib/iomgr/network_status_tracker.h \
+src/core/lib/iomgr/polling_entity.c \
+src/core/lib/iomgr/polling_entity.h \
+src/core/lib/iomgr/pollset.h \
+src/core/lib/iomgr/pollset_set.h \
+src/core/lib/iomgr/pollset_set_uv.c \
+src/core/lib/iomgr/pollset_set_windows.c \
+src/core/lib/iomgr/pollset_set_windows.h \
+src/core/lib/iomgr/pollset_uv.c \
+src/core/lib/iomgr/pollset_uv.h \
+src/core/lib/iomgr/pollset_windows.c \
+src/core/lib/iomgr/pollset_windows.h \
+src/core/lib/iomgr/port.h \
+src/core/lib/iomgr/resolve_address.h \
+src/core/lib/iomgr/resolve_address_posix.c \
+src/core/lib/iomgr/resolve_address_uv.c \
+src/core/lib/iomgr/resolve_address_windows.c \
+src/core/lib/iomgr/resource_quota.c \
+src/core/lib/iomgr/resource_quota.h \
+src/core/lib/iomgr/sockaddr.h \
+src/core/lib/iomgr/sockaddr_posix.h \
+src/core/lib/iomgr/sockaddr_utils.c \
+src/core/lib/iomgr/sockaddr_utils.h \
+src/core/lib/iomgr/sockaddr_windows.h \
+src/core/lib/iomgr/socket_mutator.c \
+src/core/lib/iomgr/socket_mutator.h \
+src/core/lib/iomgr/socket_utils.h \
+src/core/lib/iomgr/socket_utils_common_posix.c \
+src/core/lib/iomgr/socket_utils_linux.c \
+src/core/lib/iomgr/socket_utils_posix.c \
+src/core/lib/iomgr/socket_utils_posix.h \
+src/core/lib/iomgr/socket_utils_uv.c \
+src/core/lib/iomgr/socket_utils_windows.c \
+src/core/lib/iomgr/socket_windows.c \
+src/core/lib/iomgr/socket_windows.h \
+src/core/lib/iomgr/tcp_client.h \
+src/core/lib/iomgr/tcp_client_posix.c \
+src/core/lib/iomgr/tcp_client_posix.h \
+src/core/lib/iomgr/tcp_client_uv.c \
+src/core/lib/iomgr/tcp_client_windows.c \
+src/core/lib/iomgr/tcp_posix.c \
+src/core/lib/iomgr/tcp_posix.h \
+src/core/lib/iomgr/tcp_server.h \
+src/core/lib/iomgr/tcp_server_posix.c \
+src/core/lib/iomgr/tcp_server_uv.c \
+src/core/lib/iomgr/tcp_server_windows.c \
+src/core/lib/iomgr/tcp_uv.c \
+src/core/lib/iomgr/tcp_uv.h \
+src/core/lib/iomgr/tcp_windows.c \
+src/core/lib/iomgr/tcp_windows.h \
+src/core/lib/iomgr/time_averaged_stats.c \
+src/core/lib/iomgr/time_averaged_stats.h \
+src/core/lib/iomgr/timer.h \
+src/core/lib/iomgr/timer_generic.c \
+src/core/lib/iomgr/timer_generic.h \
+src/core/lib/iomgr/timer_heap.c \
+src/core/lib/iomgr/timer_heap.h \
+src/core/lib/iomgr/timer_uv.c \
+src/core/lib/iomgr/timer_uv.h \
+src/core/lib/iomgr/udp_server.c \
+src/core/lib/iomgr/udp_server.h \
+src/core/lib/iomgr/unix_sockets_posix.c \
+src/core/lib/iomgr/unix_sockets_posix.h \
+src/core/lib/iomgr/unix_sockets_posix_noop.c \
+src/core/lib/iomgr/wakeup_fd_cv.c \
+src/core/lib/iomgr/wakeup_fd_cv.h \
+src/core/lib/iomgr/wakeup_fd_eventfd.c \
+src/core/lib/iomgr/wakeup_fd_nospecial.c \
+src/core/lib/iomgr/wakeup_fd_pipe.c \
+src/core/lib/iomgr/wakeup_fd_pipe.h \
+src/core/lib/iomgr/wakeup_fd_posix.c \
+src/core/lib/iomgr/wakeup_fd_posix.h \
+src/core/lib/iomgr/workqueue.h \
+src/core/lib/iomgr/workqueue_uv.c \
+src/core/lib/iomgr/workqueue_uv.h \
+src/core/lib/iomgr/workqueue_windows.c \
+src/core/lib/iomgr/workqueue_windows.h \
+src/core/lib/json/json.c \
+src/core/lib/json/json.h \
+src/core/lib/json/json_common.h \
+src/core/lib/json/json_reader.c \
+src/core/lib/json/json_reader.h \
+src/core/lib/json/json_string.c \
+src/core/lib/json/json_writer.c \
+src/core/lib/json/json_writer.h \
 src/core/lib/profiling/basic_timers.c \
 src/core/lib/profiling/stap_timers.c \
+src/core/lib/profiling/timers.h \
+src/core/lib/security/context/security_context.c \
+src/core/lib/security/context/security_context.h \
+src/core/lib/security/credentials/composite/composite_credentials.c \
+src/core/lib/security/credentials/composite/composite_credentials.h \
+src/core/lib/security/credentials/credentials.c \
+src/core/lib/security/credentials/credentials.h \
+src/core/lib/security/credentials/credentials_metadata.c \
+src/core/lib/security/credentials/fake/fake_credentials.c \
+src/core/lib/security/credentials/fake/fake_credentials.h \
+src/core/lib/security/credentials/google_default/credentials_generic.c \
+src/core/lib/security/credentials/google_default/google_default_credentials.c \
+src/core/lib/security/credentials/google_default/google_default_credentials.h \
+src/core/lib/security/credentials/iam/iam_credentials.c \
+src/core/lib/security/credentials/iam/iam_credentials.h \
+src/core/lib/security/credentials/jwt/json_token.c \
+src/core/lib/security/credentials/jwt/json_token.h \
+src/core/lib/security/credentials/jwt/jwt_credentials.c \
+src/core/lib/security/credentials/jwt/jwt_credentials.h \
+src/core/lib/security/credentials/jwt/jwt_verifier.c \
+src/core/lib/security/credentials/jwt/jwt_verifier.h \
+src/core/lib/security/credentials/oauth2/oauth2_credentials.c \
+src/core/lib/security/credentials/oauth2/oauth2_credentials.h \
+src/core/lib/security/credentials/plugin/plugin_credentials.c \
+src/core/lib/security/credentials/plugin/plugin_credentials.h \
+src/core/lib/security/credentials/ssl/ssl_credentials.c \
+src/core/lib/security/credentials/ssl/ssl_credentials.h \
+src/core/lib/security/transport/auth_filters.h \
+src/core/lib/security/transport/client_auth_filter.c \
+src/core/lib/security/transport/secure_endpoint.c \
+src/core/lib/security/transport/secure_endpoint.h \
+src/core/lib/security/transport/security_connector.c \
+src/core/lib/security/transport/security_connector.h \
+src/core/lib/security/transport/security_handshaker.c \
+src/core/lib/security/transport/security_handshaker.h \
+src/core/lib/security/transport/server_auth_filter.c \
+src/core/lib/security/transport/tsi_error.c \
+src/core/lib/security/transport/tsi_error.h \
+src/core/lib/security/util/b64.c \
+src/core/lib/security/util/b64.h \
+src/core/lib/security/util/json_util.c \
+src/core/lib/security/util/json_util.h \
+src/core/lib/slice/percent_encoding.c \
+src/core/lib/slice/percent_encoding.h \
+src/core/lib/slice/slice.c \
+src/core/lib/slice/slice_buffer.c \
+src/core/lib/slice/slice_internal.h \
+src/core/lib/slice/slice_string_helpers.c \
+src/core/lib/slice/slice_string_helpers.h \
 src/core/lib/support/alloc.c \
 src/core/lib/support/avl.c \
 src/core/lib/support/backoff.c \
+src/core/lib/support/backoff.h \
+src/core/lib/support/block_annotate.h \
 src/core/lib/support/cmdline.c \
 src/core/lib/support/cpu_iphone.c \
 src/core/lib/support/cpu_linux.c \
 src/core/lib/support/cpu_posix.c \
 src/core/lib/support/cpu_windows.c \
+src/core/lib/support/env.h \
 src/core/lib/support/env_linux.c \
 src/core/lib/support/env_posix.c \
 src/core/lib/support/env_windows.c \
@@ -1252,29 +1226,109 @@
 src/core/lib/support/log_posix.c \
 src/core/lib/support/log_windows.c \
 src/core/lib/support/mpscq.c \
+src/core/lib/support/mpscq.h \
 src/core/lib/support/murmur_hash.c \
+src/core/lib/support/murmur_hash.h \
 src/core/lib/support/stack_lockfree.c \
+src/core/lib/support/stack_lockfree.h \
 src/core/lib/support/string.c \
+src/core/lib/support/string.h \
 src/core/lib/support/string_posix.c \
 src/core/lib/support/string_util_windows.c \
 src/core/lib/support/string_windows.c \
+src/core/lib/support/string_windows.h \
 src/core/lib/support/subprocess_posix.c \
 src/core/lib/support/subprocess_windows.c \
 src/core/lib/support/sync.c \
 src/core/lib/support/sync_posix.c \
 src/core/lib/support/sync_windows.c \
 src/core/lib/support/thd.c \
+src/core/lib/support/thd_internal.h \
 src/core/lib/support/thd_posix.c \
 src/core/lib/support/thd_windows.c \
 src/core/lib/support/time.c \
 src/core/lib/support/time_posix.c \
 src/core/lib/support/time_precise.c \
+src/core/lib/support/time_precise.h \
 src/core/lib/support/time_windows.c \
 src/core/lib/support/tls_pthread.c \
+src/core/lib/support/tmpfile.h \
 src/core/lib/support/tmpfile_msys.c \
 src/core/lib/support/tmpfile_posix.c \
 src/core/lib/support/tmpfile_windows.c \
-src/core/lib/support/wrap_memcpy.c
+src/core/lib/support/wrap_memcpy.c \
+src/core/lib/surface/README.md \
+src/core/lib/surface/alarm.c \
+src/core/lib/surface/api_trace.c \
+src/core/lib/surface/api_trace.h \
+src/core/lib/surface/byte_buffer.c \
+src/core/lib/surface/byte_buffer_reader.c \
+src/core/lib/surface/call.c \
+src/core/lib/surface/call.h \
+src/core/lib/surface/call_details.c \
+src/core/lib/surface/call_log_batch.c \
+src/core/lib/surface/call_test_only.h \
+src/core/lib/surface/channel.c \
+src/core/lib/surface/channel.h \
+src/core/lib/surface/channel_init.c \
+src/core/lib/surface/channel_init.h \
+src/core/lib/surface/channel_ping.c \
+src/core/lib/surface/channel_stack_type.c \
+src/core/lib/surface/channel_stack_type.h \
+src/core/lib/surface/completion_queue.c \
+src/core/lib/surface/completion_queue.h \
+src/core/lib/surface/event_string.c \
+src/core/lib/surface/event_string.h \
+src/core/lib/surface/init.c \
+src/core/lib/surface/init.h \
+src/core/lib/surface/init_secure.c \
+src/core/lib/surface/lame_client.c \
+src/core/lib/surface/lame_client.h \
+src/core/lib/surface/metadata_array.c \
+src/core/lib/surface/server.c \
+src/core/lib/surface/server.h \
+src/core/lib/surface/validate_metadata.c \
+src/core/lib/surface/version.c \
+src/core/lib/transport/README.md \
+src/core/lib/transport/byte_stream.c \
+src/core/lib/transport/byte_stream.h \
+src/core/lib/transport/connectivity_state.c \
+src/core/lib/transport/connectivity_state.h \
+src/core/lib/transport/mdstr_hash_table.c \
+src/core/lib/transport/mdstr_hash_table.h \
+src/core/lib/transport/metadata.c \
+src/core/lib/transport/metadata.h \
+src/core/lib/transport/metadata_batch.c \
+src/core/lib/transport/metadata_batch.h \
+src/core/lib/transport/pid_controller.c \
+src/core/lib/transport/pid_controller.h \
+src/core/lib/transport/service_config.c \
+src/core/lib/transport/service_config.h \
+src/core/lib/transport/static_metadata.c \
+src/core/lib/transport/static_metadata.h \
+src/core/lib/transport/timeout_encoding.c \
+src/core/lib/transport/timeout_encoding.h \
+src/core/lib/transport/transport.c \
+src/core/lib/transport/transport.h \
+src/core/lib/transport/transport_impl.h \
+src/core/lib/transport/transport_op_string.c \
+src/core/lib/tsi/README.md \
+src/core/lib/tsi/fake_transport_security.c \
+src/core/lib/tsi/fake_transport_security.h \
+src/core/lib/tsi/ssl_transport_security.c \
+src/core/lib/tsi/ssl_transport_security.h \
+src/core/lib/tsi/ssl_types.h \
+src/core/lib/tsi/transport_security.c \
+src/core/lib/tsi/transport_security.h \
+src/core/lib/tsi/transport_security_interface.h \
+src/core/plugin_registry/grpc_plugin_registry.c \
+third_party/nanopb/pb.h \
+third_party/nanopb/pb_common.c \
+third_party/nanopb/pb_common.h \
+third_party/nanopb/pb_decode.c \
+third_party/nanopb/pb_decode.h \
+third_party/nanopb/pb_encode.c \
+third_party/nanopb/pb_encode.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/run_tests/build_artifact_csharp.sh b/tools/jenkins/run_bazel_basic.sh
similarity index 80%
copy from tools/run_tests/build_artifact_csharp.sh
copy to tools/jenkins/run_bazel_basic.sh
index 7438713..648bc79 100755
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/tools/jenkins/run_bazel_basic.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright 2016, Google Inc.
+#!/usr/bin/env bash
+# Copyright 2017, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,12 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Test basic Bazel features
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
 
-set -ex
-
-cd $(dirname $0)/../..
-
-make grpc_csharp_ext
-
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=tools/jenkins/run_bazel_basic_in_docker.sh
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/run_tests/post_tests_csharp.sh b/tools/jenkins/run_bazel_basic_in_docker.sh
similarity index 73%
copy from tools/run_tests/post_tests_csharp.sh
copy to tools/jenkins/run_bazel_basic_in_docker.sh
index bb6f5c6..51aaa90 100755
--- a/tools/run_tests/post_tests_csharp.sh
+++ b/tools/jenkins/run_bazel_basic_in_docker.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright 2015, Google Inc.
+#!/usr/bin/env bash
+# Copyright 2017, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,18 +27,16 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Test basic Bazel features
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
 
-set -ex
-
-if [ "$CONFIG" != "gcov" ] ; then exit ; fi
-
-# change to gRPC repo root
-cd $(dirname $0)/../..
-
-# Generate the csharp extension coverage report
-gcov objs/gcov/src/csharp/ext/*.o
-lcov --base-directory . --directory . -c -o coverage.info
-lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info
-genhtml -o reports/csharp_ext_coverage --num-spaces 2 \
-  -t 'gRPC C# native extension test coverage' coverage.info \
-  --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc
+bazel build --spawn_strategy=standalone --genrule_strategy=standalone :all test/...
diff --git a/tools/run_tests/build_artifact_csharp.sh b/tools/jenkins/run_bazel_full.sh
similarity index 80%
copy from tools/run_tests/build_artifact_csharp.sh
copy to tools/jenkins/run_bazel_full.sh
index 7438713..53ed360 100755
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/tools/jenkins/run_bazel_full.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright 2016, Google Inc.
+#!/usr/bin/env bash
+# Copyright 2017, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,12 +27,12 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Test full Bazel
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
 
-set -ex
-
-cd $(dirname $0)/../..
-
-make grpc_csharp_ext
-
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
+export DOCKERFILE_DIR=tools/dockerfile/test/bazel
+export DOCKER_RUN_SCRIPT=tools/jenkins/run_bazel_full_in_docker.sh
+exec tools/run_tests/dockerize/build_and_run_docker.sh
diff --git a/tools/run_tests/post_tests_csharp.sh b/tools/jenkins/run_bazel_full_in_docker.sh
similarity index 73%
copy from tools/run_tests/post_tests_csharp.sh
copy to tools/jenkins/run_bazel_full_in_docker.sh
index bb6f5c6..19502f1 100755
--- a/tools/run_tests/post_tests_csharp.sh
+++ b/tools/jenkins/run_bazel_full_in_docker.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright 2015, Google Inc.
+#!/usr/bin/env bash
+# Copyright 2017, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,18 +27,16 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Test full Bazel
+#
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
 
-set -ex
-
-if [ "$CONFIG" != "gcov" ] ; then exit ; fi
-
-# change to gRPC repo root
-cd $(dirname $0)/../..
-
-# Generate the csharp extension coverage report
-gcov objs/gcov/src/csharp/ext/*.o
-lcov --base-directory . --directory . -c -o coverage.info
-lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info
-genhtml -o reports/csharp_ext_coverage --num-spaces 2 \
-  -t 'gRPC C# native extension test coverage' coverage.info \
-  --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix
+mkdir -p /var/local/git
+git clone /var/local/jenkins/grpc /var/local/git/grpc
+(cd /var/local/jenkins/grpc/ && git submodule foreach 'cd /var/local/git/grpc \
+&& git submodule update --init --reference /var/local/jenkins/grpc/${name} \
+${name}')
+cd /var/local/git/grpc/test
+bazel test --spawn_strategy=standalone --genrule_strategy=standalone ...
diff --git a/tools/run_tests/post_tests_csharp.sh b/tools/jenkins/run_performance_flamegraphs.sh
similarity index 64%
copy from tools/run_tests/post_tests_csharp.sh
copy to tools/jenkins/run_performance_flamegraphs.sh
index bb6f5c6..22081e2 100755
--- a/tools/run_tests/post_tests_csharp.sh
+++ b/tools/jenkins/run_performance_flamegraphs.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -27,18 +27,30 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+#
+# This script is invoked by Jenkins and runs full performance test suite.
 set -ex
 
-if [ "$CONFIG" != "gcov" ] ; then exit ; fi
-
-# change to gRPC repo root
+# Enter the gRPC repo root
 cd $(dirname $0)/../..
 
-# Generate the csharp extension coverage report
-gcov objs/gcov/src/csharp/ext/*.o
-lcov --base-directory . --directory . -c -o coverage.info
-lcov -e coverage.info '**/src/csharp/ext/*' -o coverage.info
-genhtml -o reports/csharp_ext_coverage --num-spaces 2 \
-  -t 'gRPC C# native extension test coverage' coverage.info \
-  --rc genhtml_hi_limit=95 --rc genhtml_med_limit=80 --no-prefix
+# scalability with 32cores c++ benchmarks
+tools/run_tests/run_performance_tests.py \
+    -l c++ \
+    --category scalable \
+    --remote_worker_host grpc-performance-server-32core grpc-performance-client-32core grpc-performance-client2-32core \
+    --perf_args "record -F 97 --call-graph dwarf" \
+    --flame_graph_reports cpp_flamegraphs \
+    || EXIT_CODE=1
+
+# scalability with 32cores go benchmarks
+tools/run_tests/run_performance_tests.py \
+    -l go \
+    --category scalable \
+    --remote_worker_host grpc-performance-server-32core grpc-performance-client-32core grpc-performance-client2-32core \
+    --perf_args "record -F 97 -g" \
+    --flame_graph_reports go_flamegraphs \
+    || EXIT_CODE=1
+
+exit $EXIT_CODE
+
diff --git a/tools/jenkins/run_sweep_performance.sh b/tools/jenkins/run_sweep_performance.sh
index 3b22e25..12054dc 100755
--- a/tools/jenkins/run_sweep_performance.sh
+++ b/tools/jenkins/run_sweep_performance.sh
@@ -43,6 +43,7 @@
     --category sweep \
     --bq_result_table performance_test.performance_experiment_32core \
     --remote_worker_host ${SERVER_HOST} ${CLIENT_HOST1} ${CLIENT_HOST2} \
+    --perf_args "record -F 97 --call-graph dwarf" \
     || EXIT_CODE=1
 
 exit $EXIT_CODE
diff --git a/tools/run_tests/README.md b/tools/run_tests/README.md
index dd727f4..e709ddd 100644
--- a/tools/run_tests/README.md
+++ b/tools/run_tests/README.md
@@ -22,6 +22,10 @@
 ######Example
 `tools/run_tests/run_interop_tests.py -l csharp -s c++ --use_docker` (run interop tests with C# client and C++ server)
 
+Note: if you see an error like `no space left on device` when running the
+interop tests using Docker, make sure that Docker is building the image files in
+a location with sufficient disk space.
+
 #Performance benchmarks (run_performance_tests.py)
 
 Runs predefined benchmark scenarios for given languages. Besides the simple configuration of running all the scenarios locally,
diff --git a/src/python/grpcio_reflection/grpc/__init__.py b/tools/run_tests/artifacts/__init__.py
similarity index 95%
rename from src/python/grpcio_reflection/grpc/__init__.py
rename to tools/run_tests/artifacts/__init__.py
index 70ac5ed..100a624 100644
--- a/src/python/grpcio_reflection/grpc/__init__.py
+++ b/tools/run_tests/artifacts/__init__.py
@@ -26,5 +26,3 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/tools/run_tests/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
similarity index 89%
rename from tools/run_tests/artifact_targets.py
rename to tools/run_tests/artifacts/artifact_targets.py
index 65d34e1..005d997 100644
--- a/tools/run_tests/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -35,7 +35,8 @@
 import string
 import sys
 
-import jobset
+sys.path.insert(0, os.path.abspath('..'))
+import python_utils.jobset as jobset
 
 
 def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
@@ -113,7 +114,7 @@
       environ['GRPC_BUILD_MANYLINUX_WHEEL'] = 'TRUE'
       return create_docker_jobspec(self.name,
           'tools/dockerfile/grpc_artifact_python_manylinux_%s' % self.arch,
-          'tools/run_tests/build_artifact_python.sh',
+          'tools/run_tests/artifacts/build_artifact_python.sh',
           environ=environ,
           timeout_seconds=60*60)
     elif self.platform == 'windows':
@@ -125,7 +126,7 @@
       # seed.  We create a random temp-dir here
       dir = ''.join(random.choice(string.ascii_uppercase) for _ in range(10))
       return create_jobspec(self.name,
-                            ['tools\\run_tests\\build_artifact_python.bat',
+                            ['tools\\run_tests\\artifacts\\build_artifact_python.bat',
                              self.py_version,
                              '32' if self.arch == 'x86' else '64',
                              dir
@@ -136,7 +137,7 @@
       environ['PYTHON'] = self.py_version
       environ['SKIP_PIP_INSTALL'] = 'TRUE'
       return create_jobspec(self.name,
-                            ['tools/run_tests/build_artifact_python.sh'],
+                            ['tools/run_tests/artifacts/build_artifact_python.sh'],
                             environ=environ)
 
   def __str__(self):
@@ -165,11 +166,11 @@
           environ['SETARCH_CMD'] = 'linux32'
         return create_docker_jobspec(self.name,
             'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
-            'tools/run_tests/build_artifact_ruby.sh',
+            'tools/run_tests/artifacts/build_artifact_ruby.sh',
             environ=environ)
       else:
         return create_jobspec(self.name,
-                              ['tools/run_tests/build_artifact_ruby.sh'])
+                              ['tools/run_tests/artifacts/build_artifact_ruby.sh'])
 
 
 class CSharpExtArtifact:
@@ -184,7 +185,7 @@
   def pre_build_jobspecs(self):
     if self.platform == 'windows':
       return [create_jobspec('prebuild_%s' % self.name,
-                             ['tools\\run_tests\\pre_build_c.bat'],
+                             ['tools\\run_tests\\helper_scripts\\pre_build_c.bat'],
                              shell=True,
                              flake_retries=5,
                              timeout_retries=2)]
@@ -195,7 +196,7 @@
     if self.platform == 'windows':
       msbuild_platform = 'Win32' if self.arch == 'x86' else self.arch
       return create_jobspec(self.name,
-                            ['tools\\run_tests\\build_artifact_csharp.bat',
+                            ['tools\\run_tests\\artifacts\\build_artifact_csharp.bat',
                              'vsprojects\\grpc_csharp_ext.sln',
                              '/p:Configuration=Release',
                              '/p:PlatformToolset=v120',
@@ -210,14 +211,14 @@
       if self.platform == 'linux':
         return create_docker_jobspec(self.name,
             'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
-            'tools/run_tests/build_artifact_csharp.sh',
+            'tools/run_tests/artifacts/build_artifact_csharp.sh',
             environ=environ)
       else:
         archflag = _ARCH_FLAG_MAP[self.arch]
         environ['CFLAGS'] += ' %s %s' % (archflag, _MACOS_COMPAT_FLAG)
         environ['LDFLAGS'] += ' %s' % archflag
         return create_jobspec(self.name,
-                              ['tools/run_tests/build_artifact_csharp.sh'],
+                              ['tools/run_tests/artifacts/build_artifact_csharp.sh'],
                               environ=environ)
 
   def __str__(self):
@@ -245,7 +246,7 @@
   def build_jobspec(self):
     if self.platform == 'windows':
       return create_jobspec(self.name,
-                            ['tools\\run_tests\\build_artifact_node.bat',
+                            ['tools\\run_tests\\artifacts\\build_artifact_node.bat',
                              self.gyp_arch],
                             shell=True)
     else:
@@ -253,10 +254,10 @@
         return create_docker_jobspec(
             self.name,
             'tools/dockerfile/grpc_artifact_linux_{}'.format(self.arch),
-            'tools/run_tests/build_artifact_node.sh {}'.format(self.gyp_arch))
+            'tools/run_tests/artifacts/build_artifact_node.sh {}'.format(self.gyp_arch))
       else:
         return create_jobspec(self.name,
-                              ['tools/run_tests/build_artifact_node.sh',
+                              ['tools/run_tests/artifacts/build_artifact_node.sh',
                                self.gyp_arch])
 
 class PHPArtifact:
@@ -276,10 +277,10 @@
       return create_docker_jobspec(
           self.name,
           'tools/dockerfile/grpc_artifact_linux_{}'.format(self.arch),
-          'tools/run_tests/build_artifact_php.sh')
+          'tools/run_tests/artifacts/build_artifact_php.sh')
     else:
       return create_jobspec(self.name,
-                            ['tools/run_tests/build_artifact_php.sh'])
+                            ['tools/run_tests/artifacts/build_artifact_php.sh'])
 
 class ProtocArtifact:
   """Builds protoc and protoc-plugin artifacts"""
@@ -306,18 +307,18 @@
       if self.platform == 'linux':
         return create_docker_jobspec(self.name,
             'tools/dockerfile/grpc_artifact_protoc',
-            'tools/run_tests/build_artifact_protoc.sh',
+            'tools/run_tests/artifacts/build_artifact_protoc.sh',
             environ=environ)
       else:
         environ['CXXFLAGS'] += ' -std=c++11 -stdlib=libc++ %s' % _MACOS_COMPAT_FLAG
         return create_jobspec(self.name,
-            ['tools/run_tests/build_artifact_protoc.sh'],
+            ['tools/run_tests/artifacts/build_artifact_protoc.sh'],
             environ=environ)
     else:
       generator = 'Visual Studio 12 Win64' if self.arch == 'x64' else 'Visual Studio 12' 
       vcplatform = 'x64' if self.arch == 'x64' else 'Win32'
       return create_jobspec(self.name,
-                            ['tools\\run_tests\\build_artifact_protoc.bat'],
+                            ['tools\\run_tests\\artifacts\\build_artifact_protoc.bat'],
                             environ={'generator': generator,
                                      'Platform': vcplatform})
 
diff --git a/tools/run_tests/build_artifact_csharp.bat b/tools/run_tests/artifacts/build_artifact_csharp.bat
similarity index 100%
rename from tools/run_tests/build_artifact_csharp.bat
rename to tools/run_tests/artifacts/build_artifact_csharp.bat
diff --git a/tools/run_tests/build_artifact_csharp.sh b/tools/run_tests/artifacts/build_artifact_csharp.sh
similarity index 98%
rename from tools/run_tests/build_artifact_csharp.sh
rename to tools/run_tests/artifacts/build_artifact_csharp.sh
index 7438713..aed04b2 100755
--- a/tools/run_tests/build_artifact_csharp.sh
+++ b/tools/run_tests/artifacts/build_artifact_csharp.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 make grpc_csharp_ext
 
diff --git a/tools/run_tests/build_artifact_node.bat b/tools/run_tests/artifacts/build_artifact_node.bat
similarity index 83%
rename from tools/run_tests/build_artifact_node.bat
rename to tools/run_tests/artifacts/build_artifact_node.bat
index 57d55ef..0a2bc4b 100644
--- a/tools/run_tests/build_artifact_node.bat
+++ b/tools/run_tests/artifacts/build_artifact_node.bat
@@ -27,7 +27,9 @@
 @rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set node_versions=0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0
+set node_versions=1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0
+
+set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0
 
 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm
 
@@ -47,6 +49,12 @@
 
   xcopy /Y /I /S build\stage\* artifacts\ || goto :error
 )
+
+for %%v in (%electron_versions%) do (
+  cmd /V /C "set "HOME=%HOMEDRIVE%%HOMEPATH%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package testpackage --runtime=electron --target=%%v --target_arch=%1 --disturl=https://atom.io/download/electron" || goto :error
+
+  xcopy /Y /I /S build\stage\* artifacts\ || goto :error
+)
 if %errorlevel% neq 0 exit /b %errorlevel%
 
 goto :EOF
diff --git a/tools/run_tests/build_artifact_node.sh b/tools/run_tests/artifacts/build_artifact_node.sh
similarity index 81%
rename from tools/run_tests/build_artifact_node.sh
rename to tools/run_tests/artifacts/build_artifact_node.sh
index 9d06472..47b1f33 100755
--- a/tools/run_tests/build_artifact_node.sh
+++ b/tools/run_tests/artifacts/build_artifact_node.sh
@@ -34,7 +34,7 @@
 nvm use 4
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 rm -rf build || true
 
@@ -42,10 +42,18 @@
 
 npm update
 
-node_versions=( 0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 )
+node_versions=( 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 6.0.0 7.0.0 )
+
+electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 )
 
 for version in ${node_versions[@]}
 do
   ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=$NODE_TARGET_ARCH
   cp -r build/stage/* artifacts/
 done
+
+for version in ${electron_versions[@]}
+do
+  HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --runtime=electron --target=$version --target_arch=$NODE_TARGET_ARCH --disturl=https://atom.io/download/electron
+  cp -r build/stage/* artifacts/
+done
diff --git a/tools/run_tests/build_artifact_php.sh b/tools/run_tests/artifacts/build_artifact_php.sh
similarity index 98%
rename from tools/run_tests/build_artifact_php.sh
rename to tools/run_tests/artifacts/build_artifact_php.sh
index 669447f..c8d5586 100755
--- a/tools/run_tests/build_artifact_php.sh
+++ b/tools/run_tests/artifacts/build_artifact_php.sh
@@ -31,7 +31,7 @@
 PHP_TARGET_ARCH=$1
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 mkdir -p artifacts
 
diff --git a/tools/run_tests/build_artifact_protoc.bat b/tools/run_tests/artifacts/build_artifact_protoc.bat
similarity index 96%
rename from tools/run_tests/build_artifact_protoc.bat
rename to tools/run_tests/artifacts/build_artifact_protoc.bat
index b2bf86d..fd93318 100644
--- a/tools/run_tests/build_artifact_protoc.bat
+++ b/tools/run_tests/artifacts/build_artifact_protoc.bat
@@ -34,7 +34,7 @@
 
 mkdir build & cd build
 mkdir solution & cd solution
-cmake -G "%generator%" -Dprotobuf_BUILD_TESTS=OFF ../.. || goto :error
+cmake -G "%generator%" -Dprotobuf_BUILD_TESTS=OFF ../../.. || goto :error
 endlocal
 
 call vsprojects/build_plugins.bat || goto :error
diff --git a/tools/run_tests/build_artifact_protoc.sh b/tools/run_tests/artifacts/build_artifact_protoc.sh
similarity index 98%
rename from tools/run_tests/build_artifact_protoc.sh
rename to tools/run_tests/artifacts/build_artifact_protoc.sh
index 161d3a8..26c2280 100755
--- a/tools/run_tests/build_artifact_protoc.sh
+++ b/tools/run_tests/artifacts/build_artifact_protoc.sh
@@ -33,7 +33,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 make plugins
 
diff --git a/tools/run_tests/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat
similarity index 100%
rename from tools/run_tests/build_artifact_python.bat
rename to tools/run_tests/artifacts/build_artifact_python.bat
diff --git a/tools/run_tests/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh
similarity index 99%
rename from tools/run_tests/build_artifact_python.sh
rename to tools/run_tests/artifacts/build_artifact_python.sh
index 2a1d41f..5a55060 100755
--- a/tools/run_tests/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 export GRPC_PYTHON_USE_CUSTOM_BDIST=0
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
diff --git a/tools/run_tests/build_artifact_ruby.sh b/tools/run_tests/artifacts/build_artifact_ruby.sh
similarity index 98%
rename from tools/run_tests/build_artifact_ruby.sh
rename to tools/run_tests/artifacts/build_artifact_ruby.sh
index 2d97b40..019efb0 100755
--- a/tools/run_tests/build_artifact_ruby.sh
+++ b/tools/run_tests/artifacts/build_artifact_ruby.sh
@@ -31,7 +31,7 @@
 
 SYSTEM=`uname | cut -f 1 -d_`
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 set +ex
 [[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
 [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
diff --git a/tools/run_tests/build_package_node.sh b/tools/run_tests/artifacts/build_package_node.sh
similarity index 98%
rename from tools/run_tests/build_package_node.sh
rename to tools/run_tests/artifacts/build_package_node.sh
index a5636cf..8b5e8c0 100755
--- a/tools/run_tests/build_package_node.sh
+++ b/tools/run_tests/artifacts/build_package_node.sh
@@ -33,7 +33,7 @@
 nvm use 4
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 base=$(pwd)
 
diff --git a/tools/run_tests/build_package_php.sh b/tools/run_tests/artifacts/build_package_php.sh
similarity index 98%
rename from tools/run_tests/build_package_php.sh
rename to tools/run_tests/artifacts/build_package_php.sh
index 56e3319..42a8d9f 100755
--- a/tools/run_tests/build_package_php.sh
+++ b/tools/run_tests/artifacts/build_package_php.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 mkdir -p artifacts/
 cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=php,platform={windows,linux,macos}/artifacts/* artifacts/ || true
diff --git a/tools/run_tests/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh
similarity index 98%
rename from tools/run_tests/build_package_python.sh
rename to tools/run_tests/artifacts/build_package_python.sh
index 2511a6a..4a1c15c 100755
--- a/tools/run_tests/build_package_python.sh
+++ b/tools/run_tests/artifacts/build_package_python.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 mkdir -p artifacts/
 
diff --git a/tools/run_tests/build_package_ruby.sh b/tools/run_tests/artifacts/build_package_ruby.sh
similarity index 98%
rename from tools/run_tests/build_package_ruby.sh
rename to tools/run_tests/artifacts/build_package_ruby.sh
index 0a755bd..b4d20d8 100755
--- a/tools/run_tests/build_package_ruby.sh
+++ b/tools/run_tests/artifacts/build_package_ruby.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 base=$(pwd)
 
diff --git a/tools/run_tests/distribtest_targets.py b/tools/run_tests/artifacts/distribtest_targets.py
similarity index 98%
rename from tools/run_tests/distribtest_targets.py
rename to tools/run_tests/artifacts/distribtest_targets.py
index a16daac..a7535b3 100644
--- a/tools/run_tests/distribtest_targets.py
+++ b/tools/run_tests/artifacts/distribtest_targets.py
@@ -30,7 +30,11 @@
 
 """Definition of targets run distribution package tests."""
 
-import jobset
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath('..'))
+import python_utils.jobset as jobset
 
 
 def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/artifacts/package_targets.py
similarity index 93%
rename from tools/run_tests/package_targets.py
rename to tools/run_tests/artifacts/package_targets.py
index 673affe..d490f57 100644
--- a/tools/run_tests/package_targets.py
+++ b/tools/run_tests/artifacts/package_targets.py
@@ -30,7 +30,12 @@
 
 """Definition of targets to build distribution packages."""
 
-import jobset
+import os.path
+import sys
+
+sys.path.insert(0, os.path.abspath('..'))
+import python_utils.jobset as jobset
+
 
 def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
                    flake_retries=0, timeout_retries=0):
@@ -114,7 +119,7 @@
     return create_docker_jobspec(
         self.name,
         'tools/dockerfile/grpc_artifact_linux_x64',
-        'tools/run_tests/build_package_node.sh')
+        'tools/run_tests/artifacts/build_package_node.sh')
 
 
 class RubyPackage:
@@ -131,7 +136,7 @@
     return create_docker_jobspec(
         self.name,
         'tools/dockerfile/grpc_artifact_linux_x64',
-        'tools/run_tests/build_package_ruby.sh')
+        'tools/run_tests/artifacts/build_package_ruby.sh')
 
 
 class PythonPackage:
@@ -148,7 +153,7 @@
     return create_docker_jobspec(
         self.name,
         'tools/dockerfile/grpc_artifact_linux_x64',
-        'tools/run_tests/build_package_python.sh')
+        'tools/run_tests/artifacts/build_package_python.sh')
 
 
 class PHPPackage:
@@ -165,7 +170,7 @@
     return create_docker_jobspec(
         self.name,
         'tools/dockerfile/grpc_artifact_linux_x64',
-        'tools/run_tests/build_package_php.sh')
+        'tools/run_tests/artifacts/build_package_php.sh')
 
 
 def targets():
diff --git a/tools/run_tests/build_stats_schema.json b/tools/run_tests/build_stats/build_stats_schema.json
similarity index 100%
rename from tools/run_tests/build_stats_schema.json
rename to tools/run_tests/build_stats/build_stats_schema.json
diff --git a/tools/run_tests/build_stats_schema_no_matrix.json b/tools/run_tests/build_stats/build_stats_schema_no_matrix.json
similarity index 100%
rename from tools/run_tests/build_stats_schema_no_matrix.json
rename to tools/run_tests/build_stats/build_stats_schema_no_matrix.json
diff --git a/tools/run_tests/dockerize/build_docker_and_run_tests.sh b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
index c3219c5..b68ac89 100755
--- a/tools/run_tests/dockerize/build_docker_and_run_tests.sh
+++ b/tools/run_tests/dockerize/build_docker_and_run_tests.sh
@@ -77,8 +77,6 @@
   -v /tmp/ccache:/tmp/ccache \
   -v /tmp/npm-cache:/tmp/npm-cache \
   -v /tmp/xdg-cache-home:/tmp/xdg-cache-home \
-  -v /var/run/docker.sock:/var/run/docker.sock \
-  -v $(which docker):/bin/docker \
   -w /var/local/git/grpc \
   --name=$CONTAINER_NAME \
   $DOCKER_IMAGE_NAME \
diff --git a/tools/run_tests/configs.json b/tools/run_tests/generated/configs.json
similarity index 100%
rename from tools/run_tests/configs.json
rename to tools/run_tests/generated/configs.json
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
similarity index 98%
rename from tools/run_tests/sources_and_headers.json
rename to tools/run_tests/generated/sources_and_headers.json
index 6ae269c..65379e0 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -1518,6 +1518,57 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "memory_profile_client", 
+    "src": [
+      "test/core/memory_usage/client.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "memory_profile_server", 
+    "src": [
+      "test/core/memory_usage/server.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "memory_profile_test", 
+    "src": [
+      "test/core/memory_usage/memory_usage_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "message_compress_test", 
     "src": [
       "test/core/compression/message_compress_test.c"
@@ -2774,6 +2825,23 @@
   }, 
   {
     "deps": [
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util", 
+      "http2_client_main"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "http2_client", 
+    "src": [], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "gpr_test_util", 
       "grpc", 
@@ -5390,6 +5458,33 @@
   }, 
   {
     "deps": [
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_config", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "src/proto/grpc/testing/empty.grpc.pb.h", 
+      "src/proto/grpc/testing/empty.pb.h", 
+      "src/proto/grpc/testing/messages.grpc.pb.h", 
+      "src/proto/grpc/testing/messages.pb.h", 
+      "src/proto/grpc/testing/test.grpc.pb.h", 
+      "src/proto/grpc/testing/test.pb.h", 
+      "test/cpp/interop/http2_client.h"
+    ], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "http2_client_main", 
+    "src": [
+      "test/cpp/interop/http2_client.cc", 
+      "test/cpp/interop/http2_client.h"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "grpc", 
       "grpc++", 
@@ -5447,6 +5542,7 @@
       "gpr", 
       "grpc", 
       "grpc++", 
+      "grpc++_test_util", 
       "grpc_test_util"
     ], 
     "headers": [
@@ -6681,6 +6777,8 @@
       "src/core/lib/channel/context.h", 
       "src/core/lib/channel/deadline_filter.h", 
       "src/core/lib/channel/handshaker.h", 
+      "src/core/lib/channel/handshaker_factory.h", 
+      "src/core/lib/channel/handshaker_registry.h", 
       "src/core/lib/channel/http_client_filter.h", 
       "src/core/lib/channel/http_server_filter.h", 
       "src/core/lib/channel/message_size_filter.h", 
@@ -6747,6 +6845,7 @@
       "src/core/lib/json/json_reader.h", 
       "src/core/lib/json/json_writer.h", 
       "src/core/lib/slice/percent_encoding.h", 
+      "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
@@ -6799,6 +6898,10 @@
       "src/core/lib/channel/deadline_filter.h", 
       "src/core/lib/channel/handshaker.c", 
       "src/core/lib/channel/handshaker.h", 
+      "src/core/lib/channel/handshaker_factory.c", 
+      "src/core/lib/channel/handshaker_factory.h", 
+      "src/core/lib/channel/handshaker_registry.c", 
+      "src/core/lib/channel/handshaker_registry.h", 
       "src/core/lib/channel/http_client_filter.c", 
       "src/core/lib/channel/http_client_filter.h", 
       "src/core/lib/channel/http_server_filter.c", 
@@ -6940,6 +7043,7 @@
       "src/core/lib/slice/percent_encoding.h", 
       "src/core/lib/slice/slice.c", 
       "src/core/lib/slice/slice_buffer.c", 
+      "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.c", 
       "src/core/lib/slice/slice_string_helpers.h", 
       "src/core/lib/surface/alarm.c", 
@@ -7068,6 +7172,7 @@
       "include/grpc/impl/codegen/byte_buffer_reader.h", 
       "include/grpc/impl/codegen/compression_types.h", 
       "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/exec_ctx_fwd.h", 
       "include/grpc/impl/codegen/grpc_types.h", 
       "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/status.h"
@@ -7079,6 +7184,7 @@
       "include/grpc/impl/codegen/byte_buffer_reader.h", 
       "include/grpc/impl/codegen/compression_types.h", 
       "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/exec_ctx_fwd.h", 
       "include/grpc/impl/codegen/grpc_types.h", 
       "include/grpc/impl/codegen/propagation_bits.h", 
       "include/grpc/impl/codegen/status.h"
diff --git a/tools/run_tests/tests.json b/tools/run_tests/generated/tests.json
similarity index 99%
rename from tools/run_tests/tests.json
rename to tools/run_tests/generated/tests.json
index b76263b..611ddf9 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -1570,6 +1570,26 @@
     "ci_platforms": [
       "linux", 
       "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.5, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "memory_profile_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
       "posix", 
       "windows"
     ], 
@@ -40171,6 +40191,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/08455b3ef9d516deb8155d8db7d51c43ce0ff07a"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/085865a209776911782f592c9f30ffe0ad3814a0"
     ], 
     "ci_platforms": [
@@ -40897,6 +40939,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/0d19e60f4eb1b729e272dd5dec68e8b67f03a5f4"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/0d604693a9d3e76f54d28a26142abd729b0a9acd"
     ], 
     "ci_platforms": [
@@ -41909,6 +41973,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/14064ac4844c709b247a4345a92d8be9766785c4"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/143789594154049441d565b65ce725fc4f8c12bc"
     ], 
     "ci_platforms": [
@@ -42679,6 +42765,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/1901234bd7c9cb6ee19ff8b17179c481bdc7c5f2"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/190c4ca0cf29c99bc987d2792c7f62e1007c0245"
     ], 
     "ci_platforms": [
@@ -43779,6 +43887,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/20ff1f8d5d34cb01d58aa334dc46a6644e6e1d12"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/21357c3613a47180eb668b1c6c849ce9096a46eb"
     ], 
     "ci_platforms": [
@@ -44043,6 +44173,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/2378c3f1206f20711468391ce739116ffe58374b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/23982956d17d2f55e61a5d9111b1c0c7ee530214"
     ], 
     "ci_platforms": [
@@ -48641,6 +48793,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/40640a91fda4e4e42d3063a28b9ffbba1b8c3701"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/40b4b92460c4e76a39af9042fb3d86d491a98e16"
     ], 
     "ci_platforms": [
@@ -50159,6 +50333,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/49f564289c79de9e0342f8b0821a167bc8c5ec00"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/49ff30e0f070fe37b642dd0d361c5cbca139f223"
     ], 
     "ci_platforms": [
@@ -50973,6 +51169,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/507865c4a5ce880b80400d93fa85def2682581cb"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/507b8ecbb9fd3eea9084087bce22a94cca8a7c41"
     ], 
     "ci_platforms": [
@@ -53305,6 +53523,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/5f2fdb01d8ff632803ca2b732a7c088c6843d7d3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/5f52309deaa1b641fe199889d18f921d6909fc14"
     ], 
     "ci_platforms": [
@@ -53679,6 +53919,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/61de97a9d6c4b082602c02277d8d763921f5f95b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/61f410c711bc5d53be9e932217ebd035f2716417"
     ], 
     "ci_platforms": [
@@ -53789,6 +54051,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/62b039b8a318cc08471f13629da08c68c414d8e7"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/62c995646f15be1819bd13e32a60af46297d73b4"
     ], 
     "ci_platforms": [
@@ -53987,6 +54271,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/641739453f7d4d3b55a1c7b79bed7da6dfd62ae0"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/6421db654fff309bc191aba0330fbcd1347655e3"
     ], 
     "ci_platforms": [
@@ -54229,6 +54535,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/6589505362ffb5164a3c7cb1b9feadcddfba44e9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/65afd7305e481da5ffc44a6a66eb3117744ae77d"
     ], 
     "ci_platforms": [
@@ -56143,6 +56471,50 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/724f5400f19e5a0be97022341c39eeaaaffeb390"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/7254b9ff59ab3fcf345effdabbc25ebd2e907b23"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/727f43500183aec9c0d9be7d2363fa1761cda5d5"
     ], 
     "ci_platforms": [
@@ -57133,6 +57505,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/784d6f5c093ab5360670173ce001e1a446f95822"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/788f18727a0aeb5e200527bca7c889c9954be343"
     ], 
     "ci_platforms": [
@@ -57221,6 +57615,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/79328fdc89d0af0e38da089dab062fd3ea5aae59"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/7957953ca449974ec39c6a137c0acdedb71c3b02"
     ], 
     "ci_platforms": [
@@ -57419,6 +57835,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/7a2569f4daf4480ad142cb4ee7c675bed82db74c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/7a5a769942efac79863bb154cf1e7574e6d98e22"
     ], 
     "ci_platforms": [
@@ -59399,6 +59837,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/87a300cd25d2e57745bd00499d4d2352a10a2fa1"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/87add83a18a25fe585df8adc124eae6d70733f74"
     ], 
     "ci_platforms": [
@@ -59795,6 +60255,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/8a1c629910280f8beebb88687696de98da988ecc"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/8a4183e6bb75036228a42039d678fca0ea6751b7"
     ], 
     "ci_platforms": [
@@ -60653,6 +61135,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/8ff7b1568d2da2e4196c2e28617e1911d62021e6"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/901c9a33205897999e7e78063ccdc5d363267568"
     ], 
     "ci_platforms": [
@@ -61599,6 +62103,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/982f375b183d984958667461c7767206062eb4cb"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/984b6ee241b92be62923c6dc5bacaadb36183b89"
     ], 
     "ci_platforms": [
@@ -61665,6 +62191,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/98739af631223fa05ad88f1e63a52052a9bb4b1c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/988bd333d5dabe1561cf4429e7481ff110be0da4"
     ], 
     "ci_platforms": [
@@ -63799,6 +64347,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/a78bca1ef8829d720dd5dedac3a9d4d12684da34"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/a7ccc1f7db49512983fe4d42c16b2160357e3585"
     ], 
     "ci_platforms": [
@@ -64525,6 +65095,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/ac763d89466ebfad676e75be0076831c03fe2a5d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/ac7b2971ff39a368145148524511dd68df83d522"
     ], 
     "ci_platforms": [
@@ -64987,6 +65579,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/b165523f699e6ae9b2ad15873b9d56465d1af546"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/b1e28018e26e6baaba5a907e5e6ff9b7a7942018"
     ], 
     "ci_platforms": [
@@ -65097,6 +65711,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/b2a5ec3ef40c68d594638218e3c943a479f82215"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/b2af0db70de3a6ddcb188d1f6f2a673133a8f9c7"
     ], 
     "ci_platforms": [
@@ -66241,6 +66877,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/b92b1c5e0dba009a9516e7185f5df019c62c5cc9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/b9318513eb6b1db553855cd062ebbd4d1db9b846"
     ], 
     "ci_platforms": [
@@ -68375,6 +69033,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/c5cd7af16e7bc0049445d5a0b92a3d4b7e5e3533"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/c5dbc50d9174bde5542b2bb18c63f6583a23ff13"
     ], 
     "ci_platforms": [
@@ -71873,6 +72553,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/crash-da39a3ee5e6b4b0d3255bfef95601890afd80709"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/crash-dc6abf90d5e8e1b96f7e25f418b1a7f572e6a738"
     ], 
     "ci_platforms": [
@@ -75041,6 +75743,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/e28ffd8c2816f12f6395805199c792d1718191df"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/e29bab478641dd412057dfb6b0a0d78afd96dd60"
     ], 
     "ci_platforms": [
@@ -76515,6 +77239,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/ec823f4018389e64a99f6580277fba28df6bd136"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/ec89eb7e84e6cf7859ab478362e0ae5227a5e154"
     ], 
     "ci_platforms": [
@@ -76845,6 +77591,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/ee2c1ac1e668f22836cf25a59495e778b0e2c7a8"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/ee624b408f8a50c79cdaebf4fb4195e6162b70da"
     ], 
     "ci_platforms": [
@@ -76867,6 +77635,50 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/ee6855178435d2046d8763ecae46e1e0a71a95f4"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/eeb310d91038cb02862e187e68c5d6578233485b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/eed65ac63a044c87423f333f3b9c5f0d3bc7bd3b"
     ], 
     "ci_platforms": [
@@ -77131,6 +77943,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/f07bc2907c95f2aeb79ca60e2ad826e13b848f45"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/f0a7e39c194ee3f30312ae2f4827bdbd43416a42"
     ], 
     "ci_platforms": [
@@ -78781,6 +79615,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/fb655905396b768cf3ff015afdb0b564dae2cdfd"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/fb76689d3c70bd5927b3256eda9738a2208e2b13"
     ], 
     "ci_platforms": [
@@ -79199,6 +80055,28 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/fdb038087233cd176746558875932029f779221d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/fdecd05733278ece9993eb2bef13917675cc062c"
     ], 
     "ci_platforms": [
diff --git a/tools/run_tests/build_csharp.sh b/tools/run_tests/helper_scripts/build_csharp.sh
similarity index 97%
rename from tools/run_tests/build_csharp.sh
rename to tools/run_tests/helper_scripts/build_csharp.sh
index 48ce11a..84c5b1c 100755
--- a/tools/run_tests/build_csharp.sh
+++ b/tools/run_tests/helper_scripts/build_csharp.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../src/csharp
+cd $(dirname $0)/../../../src/csharp
 
 # overriding NativeDependenciesConfigurationUnix is needed to make gcov code coverage work.
 xbuild /p:Configuration=$MSBUILD_CONFIG /p:NativeDependenciesConfigurationUnix=$CONFIG Grpc.sln
diff --git a/tools/run_tests/build_csharp_coreclr.bat b/tools/run_tests/helper_scripts/build_csharp_coreclr.bat
similarity index 97%
rename from tools/run_tests/build_csharp_coreclr.bat
rename to tools/run_tests/helper_scripts/build_csharp_coreclr.bat
index b6e3ccb..78e5f59 100644
--- a/tools/run_tests/build_csharp_coreclr.bat
+++ b/tools/run_tests/helper_scripts/build_csharp_coreclr.bat
@@ -29,7 +29,7 @@
 
 setlocal
 
-cd /d %~dp0\..\..\src\csharp
+cd /d %~dp0\..\..\..\src\csharp
 
 dotnet restore . || goto :error
 
diff --git a/tools/run_tests/build_csharp_coreclr.sh b/tools/run_tests/helper_scripts/build_csharp_coreclr.sh
similarity index 97%
rename from tools/run_tests/build_csharp_coreclr.sh
rename to tools/run_tests/helper_scripts/build_csharp_coreclr.sh
index 02cf0d3..dd5fd31 100755
--- a/tools/run_tests/build_csharp_coreclr.sh
+++ b/tools/run_tests/helper_scripts/build_csharp_coreclr.sh
@@ -30,7 +30,7 @@
 
 set -ex
 
-cd $(dirname $0)/../../src/csharp
+cd $(dirname $0)/../../../src/csharp
 
 # TODO(jtattermusch): introduce caching
 dotnet restore .
diff --git a/tools/run_tests/build_node.bat b/tools/run_tests/helper_scripts/build_node.bat
similarity index 100%
rename from tools/run_tests/build_node.bat
rename to tools/run_tests/helper_scripts/build_node.bat
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/helper_scripts/build_node.sh
similarity index 98%
rename from tools/run_tests/build_node.sh
rename to tools/run_tests/helper_scripts/build_node.sh
index d9292fd..8a928bb 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/helper_scripts/build_node.sh
@@ -38,6 +38,6 @@
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 npm install --unsafe-perm --build-from-source
diff --git a/tools/run_tests/build_artifact_protoc.sh b/tools/run_tests/helper_scripts/build_node_electron.sh
similarity index 82%
copy from tools/run_tests/build_artifact_protoc.sh
copy to tools/run_tests/helper_scripts/build_node_electron.sh
index 161d3a8..1c95c51 100755
--- a/tools/run_tests/build_artifact_protoc.sh
+++ b/tools/run_tests/helper_scripts/build_node_electron.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,14 +29,18 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Use devtoolset environment that has GCC 4.7 before set -ex
-source scl_source enable devtoolset-1.1
+ELECTRON_VERSION=$1
+source ~/.nvm/nvm.sh
 
+nvm use 6
 set -ex
 
+# change to grpc repo root
 cd $(dirname $0)/../..
 
-make plugins
-
-mkdir -p artifacts
-cp bins/opt/protobuf/protoc bins/opt/*_plugin artifacts/
+export npm_config_target=$ELECTRON_VERSION
+export npm_config_disturl=https://atom.io/download/atom-shell
+export npm_config_runtime=electron
+export npm_config_build_from_source=true
+mkdir -p ~/.electron-gyp
+HOME=~/.electron-gyp npm install --unsafe-perm
diff --git a/tools/run_tests/build_php.sh b/tools/run_tests/helper_scripts/build_php.sh
similarity index 98%
rename from tools/run_tests/build_php.sh
rename to tools/run_tests/helper_scripts/build_php.sh
index 77a8abc..acaaa23 100755
--- a/tools/run_tests/build_php.sh
+++ b/tools/run_tests/helper_scripts/build_php.sh
@@ -33,7 +33,7 @@
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 root=`pwd`
 export GRPC_LIB_SUBDIR=libs/$CONFIG
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
similarity index 99%
rename from tools/run_tests/build_python.sh
rename to tools/run_tests/helper_scripts/build_python.sh
index 7cac394..0e88e96 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -31,7 +31,7 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 ##########################
 # Portability operations #
diff --git a/tools/run_tests/build_python_msys2.sh b/tools/run_tests/helper_scripts/build_python_msys2.sh
similarity index 100%
rename from tools/run_tests/build_python_msys2.sh
rename to tools/run_tests/helper_scripts/build_python_msys2.sh
diff --git a/tools/run_tests/build_ruby.sh b/tools/run_tests/helper_scripts/build_ruby.sh
similarity index 98%
rename from tools/run_tests/build_ruby.sh
rename to tools/run_tests/helper_scripts/build_ruby.sh
index 10343fc..32638de 100755
--- a/tools/run_tests/build_ruby.sh
+++ b/tools/run_tests/helper_scripts/build_ruby.sh
@@ -34,7 +34,7 @@
 export GRPC_CONFIG=${CONFIG:-opt}
 
 # change to grpc's ruby directory
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 rm -rf ./tmp
 rake compile
diff --git a/tools/run_tests/post_tests_c.sh b/tools/run_tests/helper_scripts/post_tests_c.sh
similarity index 97%
rename from tools/run_tests/post_tests_c.sh
rename to tools/run_tests/helper_scripts/post_tests_c.sh
index 4409526..a83a59e 100755
--- a/tools/run_tests/post_tests_c.sh
+++ b/tools/run_tests/helper_scripts/post_tests_c.sh
@@ -32,7 +32,7 @@
 
 if [ "$CONFIG" != "gcov" ] ; then exit ; fi
 
-root=$(readlink -f $(dirname $0)/../..)
+root=$(readlink -f $(dirname $0)/../../..)
 out=$root/reports/c_cxx_coverage
 tmp1=$(mktemp)
 tmp2=$(mktemp)
diff --git a/tools/run_tests/post_tests_csharp.bat b/tools/run_tests/helper_scripts/post_tests_csharp.bat
similarity index 98%
rename from tools/run_tests/post_tests_csharp.bat
rename to tools/run_tests/helper_scripts/post_tests_csharp.bat
index 0d49a00..2359f14 100644
--- a/tools/run_tests/post_tests_csharp.bat
+++ b/tools/run_tests/helper_scripts/post_tests_csharp.bat
@@ -36,7 +36,7 @@
 )
 
 @rem enter src/csharp directory
-cd /d %~dp0\..\..\src\csharp
+cd /d %~dp0\..\..\..\src\csharp
 
 @rem Generate code coverage report
 @rem TODO(jtattermusch): currently the report list is hardcoded
diff --git a/tools/run_tests/post_tests_csharp.sh b/tools/run_tests/helper_scripts/post_tests_csharp.sh
similarity index 98%
rename from tools/run_tests/post_tests_csharp.sh
rename to tools/run_tests/helper_scripts/post_tests_csharp.sh
index bb6f5c6..762c1f8 100755
--- a/tools/run_tests/post_tests_csharp.sh
+++ b/tools/run_tests/helper_scripts/post_tests_csharp.sh
@@ -33,7 +33,7 @@
 if [ "$CONFIG" != "gcov" ] ; then exit ; fi
 
 # change to gRPC repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 # Generate the csharp extension coverage report
 gcov objs/gcov/src/csharp/ext/*.o
diff --git a/tools/run_tests/post_tests_php.sh b/tools/run_tests/helper_scripts/post_tests_php.sh
similarity index 97%
rename from tools/run_tests/post_tests_php.sh
rename to tools/run_tests/helper_scripts/post_tests_php.sh
index b409806..23dc202 100755
--- a/tools/run_tests/post_tests_php.sh
+++ b/tools/run_tests/helper_scripts/post_tests_php.sh
@@ -32,7 +32,7 @@
 
 if [ "$CONFIG" != "gcov" ] ; then exit ; fi
 
-root=$(readlink -f $(dirname $0)/../..)
+root=$(readlink -f $(dirname $0)/../../..)
 out=$root/reports/php_ext_coverage
 tmp1=$(mktemp)
 tmp2=$(mktemp)
diff --git a/tools/run_tests/post_tests_ruby.sh b/tools/run_tests/helper_scripts/post_tests_ruby.sh
similarity index 97%
rename from tools/run_tests/post_tests_ruby.sh
rename to tools/run_tests/helper_scripts/post_tests_ruby.sh
index 0877e44..300edfe 100755
--- a/tools/run_tests/post_tests_ruby.sh
+++ b/tools/run_tests/helper_scripts/post_tests_ruby.sh
@@ -32,7 +32,7 @@
 
 if [ "$CONFIG" != "gcov" ] ; then exit ; fi
 
-root=$(readlink -f $(dirname $0)/../..)
+root=$(readlink -f $(dirname $0)/../../..)
 out=$root/reports/ruby_ext_coverage
 tmp1=$(mktemp)
 tmp2=$(mktemp)
diff --git a/tools/run_tests/pre_build_c.bat b/tools/run_tests/helper_scripts/pre_build_c.bat
similarity index 98%
rename from tools/run_tests/pre_build_c.bat
rename to tools/run_tests/helper_scripts/pre_build_c.bat
index e4ab693..75b90f8 100644
--- a/tools/run_tests/pre_build_c.bat
+++ b/tools/run_tests/helper_scripts/pre_build_c.bat
@@ -32,7 +32,7 @@
 setlocal
 
 @rem enter repo root
-cd /d %~dp0\..\..
+cd /d %~dp0\..\..\..
 
 @rem Location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
diff --git a/tools/run_tests/pre_build_csharp.bat b/tools/run_tests/helper_scripts/pre_build_csharp.bat
similarity index 99%
rename from tools/run_tests/pre_build_csharp.bat
rename to tools/run_tests/helper_scripts/pre_build_csharp.bat
index f15979a..139955d 100644
--- a/tools/run_tests/pre_build_csharp.bat
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.bat
@@ -32,7 +32,7 @@
 setlocal
 
 @rem enter repo root
-cd /d %~dp0\..\..
+cd /d %~dp0\..\..\..
 
 @rem Location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
diff --git a/tools/run_tests/pre_build_csharp.sh b/tools/run_tests/helper_scripts/pre_build_csharp.sh
similarity index 98%
rename from tools/run_tests/pre_build_csharp.sh
rename to tools/run_tests/helper_scripts/pre_build_csharp.sh
index ee678dd..1f80855 100755
--- a/tools/run_tests/pre_build_csharp.sh
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.sh
@@ -31,7 +31,7 @@
 set -ex
 
 # cd to gRPC csharp directory
-cd $(dirname $0)/../../src/csharp
+cd $(dirname $0)/../../../src/csharp
 
 root=`pwd`
 
diff --git a/tools/run_tests/pre_build_node.bat b/tools/run_tests/helper_scripts/pre_build_node.bat
similarity index 100%
rename from tools/run_tests/pre_build_node.bat
rename to tools/run_tests/helper_scripts/pre_build_node.bat
diff --git a/tools/run_tests/pre_build_node.sh b/tools/run_tests/helper_scripts/pre_build_node.sh
similarity index 100%
rename from tools/run_tests/pre_build_node.sh
rename to tools/run_tests/helper_scripts/pre_build_node.sh
diff --git a/tools/run_tests/build_artifact_php.sh b/tools/run_tests/helper_scripts/pre_build_node_electron.sh
similarity index 93%
copy from tools/run_tests/build_artifact_php.sh
copy to tools/run_tests/helper_scripts/pre_build_node_electron.sh
index 669447f..95c56aa 100755
--- a/tools/run_tests/build_artifact_php.sh
+++ b/tools/run_tests/helper_scripts/pre_build_node_electron.sh
@@ -1,4 +1,5 @@
 #!/bin/bash
+
 # Copyright 2016, Google Inc.
 # All rights reserved.
 #
@@ -28,13 +29,11 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-PHP_TARGET_ARCH=$1
+ELECTRON_VERSION=$1
+
+nvm install 6
 set -ex
 
-cd $(dirname $0)/../..
+npm install xvfb-maybe
 
-mkdir -p artifacts
-
-pear package
-
-cp -r grpc-*.tgz artifacts/
+npm install electron@$ELECTRON_VERSION
diff --git a/tools/run_tests/pre_build_ruby.sh b/tools/run_tests/helper_scripts/pre_build_ruby.sh
similarity index 98%
rename from tools/run_tests/pre_build_ruby.sh
rename to tools/run_tests/helper_scripts/pre_build_ruby.sh
index e7074c4..56b58df 100755
--- a/tools/run_tests/pre_build_ruby.sh
+++ b/tools/run_tests/helper_scripts/pre_build_ruby.sh
@@ -34,6 +34,6 @@
 export GRPC_CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 bundle install
diff --git a/tools/run_tests/run_lcov.sh b/tools/run_tests/helper_scripts/run_lcov.sh
similarity index 97%
rename from tools/run_tests/run_lcov.sh
rename to tools/run_tests/helper_scripts/run_lcov.sh
index 796a0b5..bc7b44c 100755
--- a/tools/run_tests/run_lcov.sh
+++ b/tools/run_tests/helper_scripts/run_lcov.sh
@@ -32,7 +32,7 @@
 
 out=$(readlink -f ${1:-coverage})
 
-root=$(readlink -f $(dirname $0)/../..)
+root=$(readlink -f $(dirname $0)/../../..)
 shift || true
 tmp=$(mktemp)
 cd $root
diff --git a/tools/run_tests/run_node.bat b/tools/run_tests/helper_scripts/run_node.bat
similarity index 100%
rename from tools/run_tests/run_node.bat
rename to tools/run_tests/helper_scripts/run_node.bat
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/helper_scripts/run_node.sh
similarity index 98%
rename from tools/run_tests/run_node.sh
rename to tools/run_tests/helper_scripts/run_node.sh
index 44f7564..0fafe94 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/helper_scripts/run_node.sh
@@ -37,7 +37,7 @@
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 root=`pwd`
 
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/helper_scripts/run_node_electron.sh
similarity index 85%
copy from tools/run_tests/build_node.sh
copy to tools/run_tests/helper_scripts/run_node_electron.sh
index d9292fd..1999ffb 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/helper_scripts/run_node_electron.sh
@@ -1,5 +1,4 @@
 #!/bin/bash
-
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -29,15 +28,18 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-NODE_VERSION=$1
 source ~/.nvm/nvm.sh
 
-nvm use $NODE_VERSION
+nvm use 6
 set -ex
 
-CONFIG=${CONFIG:-opt}
-
 # change to grpc repo root
 cd $(dirname $0)/../..
 
-npm install --unsafe-perm --build-from-source
+test_directory='src/node/test'
+timeout=8000
+
+JUNIT_REPORT_PATH=src/node/report.xml JUNIT_REPORT_STACK=1 \
+  ./node_modules/.bin/xvfb-maybe \
+  ./node_modules/.bin/electron-mocha --timeout $timeout \
+  --reporter mocha-jenkins-reporter $test_directory
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/helper_scripts/run_python.sh
similarity index 98%
rename from tools/run_tests/run_python.sh
rename to tools/run_tests/helper_scripts/run_python.sh
index 17e0186..7be4734 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/helper_scripts/run_python.sh
@@ -31,7 +31,7 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 PYTHON=`realpath -s "${1:-py27/bin/python}"`
 
diff --git a/tools/run_tests/run_ruby.sh b/tools/run_tests/helper_scripts/run_ruby.sh
similarity index 98%
rename from tools/run_tests/run_ruby.sh
rename to tools/run_tests/helper_scripts/run_ruby.sh
index 73a84ac..ab153b7 100755
--- a/tools/run_tests/run_ruby.sh
+++ b/tools/run_tests/helper_scripts/run_ruby.sh
@@ -31,6 +31,6 @@
 set -ex
 
 # change to grpc repo root
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 
 rake
diff --git a/tools/run_tests/run_tests_in_workspace.sh b/tools/run_tests/helper_scripts/run_tests_in_workspace.sh
similarity index 98%
rename from tools/run_tests/run_tests_in_workspace.sh
rename to tools/run_tests/helper_scripts/run_tests_in_workspace.sh
index 9c6c5b7..002c8d6 100755
--- a/tools/run_tests/run_tests_in_workspace.sh
+++ b/tools/run_tests/helper_scripts/run_tests_in_workspace.sh
@@ -34,7 +34,7 @@
 # newly created workspace)
 set -ex
 
-cd $(dirname $0)/../..
+cd $(dirname $0)/../../..
 export repo_root=$(pwd)
 
 rm -rf "${WORKSPACE_NAME}"
diff --git a/tools/run_tests/interop_html_report.template b/tools/run_tests/interop/interop_html_report.template
similarity index 100%
rename from tools/run_tests/interop_html_report.template
rename to tools/run_tests/interop/interop_html_report.template
diff --git a/tools/run_tests/performance/bq_upload_result.py b/tools/run_tests/performance/bq_upload_result.py
index ddcf053..89d2a9b 100755
--- a/tools/run_tests/performance/bq_upload_result.py
+++ b/tools/run_tests/performance/bq_upload_result.py
@@ -115,9 +115,11 @@
   scenario_result['scenario']['clientConfig'] = json.dumps(scenario_result['scenario']['clientConfig'])
   scenario_result['scenario']['serverConfig'] = json.dumps(scenario_result['scenario']['serverConfig'])
   scenario_result['latencies'] = json.dumps(scenario_result['latencies'])
+  scenario_result['serverCpuStats'] = []
   for stats in scenario_result['serverStats']:
-    stats.pop('totalCpuTime', None)
-    stats.pop('idleCpuTime', None)
+    scenario_result['serverCpuStats'].append(dict())
+    scenario_result['serverCpuStats'][-1]['totalCpuTime'] = stats.pop('totalCpuTime', None)
+    scenario_result['serverCpuStats'][-1]['idleCpuTime'] = stats.pop('idleCpuTime', None)
   for stats in scenario_result['clientStats']:
     stats['latencies'] = json.dumps(stats['latencies'])
     stats.pop('requestResults', None)
@@ -125,7 +127,7 @@
   scenario_result['clientSuccess'] = json.dumps(scenario_result['clientSuccess'])
   scenario_result['serverSuccess'] = json.dumps(scenario_result['serverSuccess'])
   scenario_result['requestResults'] = json.dumps(scenario_result.get('requestResults', []))
-  scenario_result['summary'].pop('serverCpuUsage', None)
+  scenario_result['serverCpuUsage'] = scenario_result['summary'].pop('serverCpuUsage', None)
   scenario_result['summary'].pop('successfulRequestsPerSecond', None)
   scenario_result['summary'].pop('failedRequestsPerSecond', None)
 
diff --git a/tools/run_tests/performance/scenario_result_schema.json b/tools/run_tests/performance/scenario_result_schema.json
index 3285f21..8ec41c3 100644
--- a/tools/run_tests/performance/scenario_result_schema.json
+++ b/tools/run_tests/performance/scenario_result_schema.json
@@ -213,5 +213,27 @@
     "name": "requestResults",
     "type": "STRING",
     "mode": "NULLABLE"
+  },
+  {
+    "name": "serverCpuStats",
+    "type": "RECORD",
+    "mode": "REPEATED",
+    "fields": [
+      {
+        "name": "totalCpuTime",
+        "type": "INTEGER",
+        "mode": "NULLABLE"
+      },
+      {
+        "name": "idleCpuTime",
+        "type": "INTEGER",
+        "mode": "NULLABLE"
+      }
+    ]
+  },
+  {
+    "name": "serverCpuUsage",
+    "type": "FLOAT",
+    "mode": "NULLABLE"
   }
 ]
diff --git a/tools/run_tests/prepare_travis.sh b/tools/run_tests/prepare_travis.sh
deleted file mode 100755
index 1054653..0000000
--- a/tools/run_tests/prepare_travis.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/bash
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-cd `dirname $0`/../..
-grpc_dir=`pwd`
-
-distrib=`md5sum /etc/issue | cut -f1 -d\ `
-echo "Configuring for distribution $distrib"
-git submodule | while read sha path extra ; do
-  cd /tmp
-  name=`basename $path`
-  file=$name-$sha-$CONFIG-prebuilt-$distrib.tar.gz
-  echo -n "Looking for $file ..."
-  url=http://storage.googleapis.com/grpc-prebuilt-packages/$file
-  wget -q $url && (
-    echo " Found."
-    tar xfz $file
-  ) || echo " Not found."
-done
-
-mkdir -p bins/$CONFIG/protobuf
-mkdir -p libs/$CONFIG/protobuf
-mkdir -p libs/$CONFIG/openssl
-
-function cpt {
-  cp /tmp/prebuilt/$1 $2/$CONFIG/$3
-  touch $2/$CONFIG/$3/`basename $1`
-}
-
-if [ -e /tmp/prebuilt/bin/protoc ] ; then
-  touch third_party/protobuf/configure
-  cpt bin/protoc bins protobuf
-  cpt lib/libprotoc.a libs protobuf
-  cpt lib/libprotobuf.a libs protobuf
-fi
-
-if [ -e /tmp/prebuilt/lib/libssl.a ] ; then
-  cpt lib/libcrypto.a libs openssl
-  cpt lib/libssl.a libs openssl
-fi
diff --git a/src/python/grpcio_reflection/grpc/__init__.py b/tools/run_tests/python_utils/__init__.py
similarity index 95%
copy from src/python/grpcio_reflection/grpc/__init__.py
copy to tools/run_tests/python_utils/__init__.py
index 70ac5ed..100a624 100644
--- a/src/python/grpcio_reflection/grpc/__init__.py
+++ b/tools/run_tests/python_utils/__init__.py
@@ -26,5 +26,3 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/tools/run_tests/antagonist.py b/tools/run_tests/python_utils/antagonist.py
similarity index 100%
rename from tools/run_tests/antagonist.py
rename to tools/run_tests/python_utils/antagonist.py
diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/python_utils/dockerjob.py
similarity index 99%
rename from tools/run_tests/dockerjob.py
rename to tools/run_tests/python_utils/dockerjob.py
index 4a7e61b..0869c5c 100755
--- a/tools/run_tests/dockerjob.py
+++ b/tools/run_tests/python_utils/dockerjob.py
@@ -31,13 +31,14 @@
 
 from __future__ import print_function
 
-import jobset
 import tempfile
 import time
 import uuid
 import os
 import subprocess
 
+import jobset
+
 _DEVNULL = open(os.devnull, 'w')
 
 
diff --git a/tools/run_tests/filter_pull_request_tests.py b/tools/run_tests/python_utils/filter_pull_request_tests.py
similarity index 100%
rename from tools/run_tests/filter_pull_request_tests.py
rename to tools/run_tests/python_utils/filter_pull_request_tests.py
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/python_utils/jobset.py
similarity index 93%
rename from tools/run_tests/jobset.py
rename to tools/run_tests/python_utils/jobset.py
index 1b5d6d6..7b2c62d 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -219,7 +219,8 @@
 class Job(object):
   """Manages one job."""
 
-  def __init__(self, spec, newline_on_success, travis, add_env):
+  def __init__(self, spec, newline_on_success, travis, add_env,
+               quiet_success=False):
     self._spec = spec
     self._newline_on_success = newline_on_success
     self._travis = travis
@@ -227,7 +228,9 @@
     self._retries = 0
     self._timeout_retries = 0
     self._suppress_failure_message = False
-    message('START', spec.shortname, do_newline=self._travis)
+    self._quiet_success = quiet_success
+    if not self._quiet_success:
+      message('START', spec.shortname, do_newline=self._travis)
     self.result = JobResult()
     self.start()
 
@@ -302,10 +305,11 @@
           if real > 0.5:
             cores = (user + sys) / real
             measurement = '; cpu_cost=%.01f; estimated=%.01f' % (cores, self._spec.cpu_cost)
-        message('PASSED', '%s [time=%.1fsec; retries=%d:%d%s]' % (
-            self._spec.shortname, elapsed, self._retries, self._timeout_retries, measurement),
-            stdout() if self._spec.verbose_success else None,
-            do_newline=self._newline_on_success or self._travis)
+        if not self._quiet_success:
+          message('PASSED', '%s [time=%.1fsec; retries=%d:%d%s]' % (
+              self._spec.shortname, elapsed, self._retries, self._timeout_retries, measurement),
+              stdout() if self._spec.verbose_success else None,
+              do_newline=self._newline_on_success or self._travis)
         self.result.state = 'PASSED'
     elif (self._state == _RUNNING and
           self._spec.timeout_seconds is not None and
@@ -341,7 +345,7 @@
   """Manages one run of jobs."""
 
   def __init__(self, check_cancelled, maxjobs, newline_on_success, travis,
-               stop_on_failure, add_env):
+               stop_on_failure, add_env, quiet_success):
     self._running = set()
     self._check_cancelled = check_cancelled
     self._cancelled = False
@@ -352,6 +356,7 @@
     self._travis = travis
     self._stop_on_failure = stop_on_failure
     self._add_env = add_env
+    self._quiet_success = quiet_success
     self.resultset = {}
     self._remaining = None
     self._start_time = time.time()
@@ -380,7 +385,8 @@
     job = Job(spec,
               self._newline_on_success,
               self._travis,
-              self._add_env)
+              self._add_env,
+              self._quiet_success)
     self._running.add(job)
     if job.GetSpec().shortname not in self.resultset:
       self.resultset[job.GetSpec().shortname] = []
@@ -403,7 +409,8 @@
         break
       for job in dead:
         self._completed += 1
-        self.resultset[job.GetSpec().shortname].append(job.result)
+        if not self._quiet_success or job.result.state != 'PASSED':
+          self.resultset[job.GetSpec().shortname].append(job.result)
         self._running.remove(job)
       if dead: return
       if not self._travis and platform_string() != 'windows':
@@ -463,7 +470,8 @@
         infinite_runs=False,
         stop_on_failure=False,
         add_env={},
-        skip_jobs=False):
+        skip_jobs=False,
+        quiet_success=False):
   if skip_jobs:
     results = {}
     skipped_job_result = JobResult()
@@ -474,7 +482,8 @@
     return results
   js = Jobset(check_cancelled,
               maxjobs if maxjobs is not None else _DEFAULT_MAX_JOBS,
-              newline_on_success, travis, stop_on_failure, add_env)
+              newline_on_success, travis, stop_on_failure, add_env,
+              quiet_success)
   for cmdline, remaining in tag_remaining(cmdlines):
     if not js.start(cmdline):
       break
diff --git a/tools/run_tests/port_server.py b/tools/run_tests/python_utils/port_server.py
similarity index 100%
rename from tools/run_tests/port_server.py
rename to tools/run_tests/python_utils/port_server.py
diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/python_utils/report_utils.py
similarity index 98%
rename from tools/run_tests/report_utils.py
rename to tools/run_tests/python_utils/report_utils.py
index 5ce2a87..352cf7a 100644
--- a/tools/run_tests/report_utils.py
+++ b/tools/run_tests/python_utils/report_utils.py
@@ -84,7 +84,7 @@
   client_langs, server_langs, test_cases, auth_test_cases, http2_cases,
   resultset, num_failures, cloud_to_prod, prod_servers, http2_interop):
   """Generate HTML report for interop tests."""
-  template_file = 'tools/run_tests/interop_html_report.template'
+  template_file = 'tools/run_tests/interop/interop_html_report.template'
   try:
     mytemplate = Template(filename=template_file, format_exceptions=True)
   except NameError:
diff --git a/tools/run_tests/watch_dirs.py b/tools/run_tests/python_utils/watch_dirs.py
similarity index 100%
rename from tools/run_tests/watch_dirs.py
rename to tools/run_tests/python_utils/watch_dirs.py
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 83cfc42..56efac5 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -34,20 +34,21 @@
 
 import argparse
 import atexit
-import dockerjob
 import itertools
-import jobset
 import json
 import multiprocessing
 import os
 import re
-import report_utils
 import subprocess
 import sys
 import tempfile
 import time
 import uuid
 
+import python_utils.dockerjob as dockerjob
+import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
+
 # Docker doesn't clean up after itself, so we do it on exit.
 atexit.register(lambda: subprocess.call(['stty', 'echo']))
 
@@ -168,6 +169,9 @@
   def client_cmd(self, args):
     return ['./run-test-client.sh'] + args
 
+  def client_cmd_http2interop(self, args):
+    return ['./run-http2-client.sh'] + args
+
   def cloud_to_prod_env(self):
     return {}
 
@@ -178,10 +182,10 @@
     return {}
 
   def unimplemented_test_cases(self):
-    return _SKIP_ADVANCED + _SKIP_COMPRESSION
+    return _SKIP_COMPRESSION
 
   def unimplemented_test_cases_server(self):
-    return _SKIP_ADVANCED + _SKIP_COMPRESSION
+    return _SKIP_COMPRESSION
 
   def __str__(self):
     return 'java'
@@ -216,6 +220,33 @@
   def __str__(self):
     return 'go'
 
+class Http2Server:
+  """Represents the HTTP/2 Interop Test server
+
+  This pretends to be a language in order to be built and run, but really it
+  isn't.
+  """
+  def __init__(self):
+    self.server_cwd = None
+    self.safename = str(self)
+
+  def server_cmd(self, args):
+    return ['python test/http2_test/http2_test_server.py']
+
+  def cloud_to_prod_env(self):
+    return {}
+
+  def global_env(self):
+    return {}
+
+  def unimplemented_test_cases(self):
+    return _TEST_CASES
+
+  def unimplemented_test_cases_server(self):
+    return _TEST_CASES
+
+  def __str__(self):
+    return 'http2'
 
 class Http2Client:
   """Represents the HTTP/2 Interop Test
@@ -349,10 +380,10 @@
     return {}
 
   def unimplemented_test_cases(self):
-    return _SKIP_ADVANCED + _SKIP_SERVER_COMPRESSION
+    return _SKIP_SERVER_COMPRESSION
 
   def unimplemented_test_cases_server(self):
-    return _SKIP_ADVANCED + _SKIP_COMPRESSION
+    return _SKIP_COMPRESSION
 
   def __str__(self):
     return 'ruby'
@@ -374,6 +405,11 @@
         '--args="{}"'.format(' '.join(args))
     ]
 
+  def client_cmd_http2interop(self, args):
+    return [ 'py27/bin/python',
+              'src/python/grpcio_tests/tests/http2/_negative_http2_client.py',
+           ] + args
+
   def cloud_to_prod_env(self):
     return {}
 
@@ -428,7 +464,10 @@
 _AUTH_TEST_CASES = ['compute_engine_creds', 'jwt_token_creds',
                     'oauth2_auth_token', 'per_rpc_creds']
 
-_HTTP2_TEST_CASES = ["tls", "framing"]
+_HTTP2_TEST_CASES = ['tls', 'framing']
+
+_HTTP2_BADSERVER_TEST_CASES = ['rst_after_header', 'rst_after_data', 'rst_during_data',
+                     'goaway', 'ping', 'max_streams']
 
 DOCKER_WORKDIR_ROOT = '/var/local/git/grpc'
 
@@ -549,13 +588,25 @@
 def cloud_to_cloud_jobspec(language, test_case, server_name, server_host,
                            server_port, docker_image=None):
   """Creates jobspec for cloud-to-cloud interop test"""
-  cmdline = bash_cmdline(language.client_cmd([
+  interop_only_options = [
       '--server_host_override=foo.test.google.fr',
       '--use_tls=true',
       '--use_test_ca=true',
+  ]
+  common_options = [
       '--test_case=%s' % test_case,
       '--server_host=%s' % server_host,
-      '--server_port=%s' % server_port]))
+  ]
+  if test_case in _HTTP2_BADSERVER_TEST_CASES:
+    # We are running the http2_badserver_interop test. Adjust command line accordingly.
+    offset = sorted(_HTTP2_BADSERVER_TEST_CASES).index(test_case)
+    client_options = common_options + ['--server_port=%s' %
+                                       (int(server_port)+offset)]
+    cmdline = bash_cmdline(language.client_cmd_http2interop(client_options))
+  else:
+    client_options = interop_only_options + common_options + ['--server_port=%s' % server_port]
+    cmdline = bash_cmdline(language.client_cmd(client_options))
+
   cwd = language.client_cwd
   environ = language.global_env()
   if docker_image:
@@ -589,13 +640,30 @@
   cmdline = bash_cmdline(
       language.server_cmd(['--port=%s' % _DEFAULT_SERVER_PORT]))
   environ = language.global_env()
+  if language.safename == 'http2':
+    # we are running the http2 interop server. Open next N ports beginning
+    # with the server port. These ports are used for http2 interop test
+    # (one test case per port). We also attach the docker container running
+    # the server to local network, so we don't have to mess with port mapping
+    port_args = [
+      '-p', str(_DEFAULT_SERVER_PORT+0),
+      '-p', str(_DEFAULT_SERVER_PORT+1),
+      '-p', str(_DEFAULT_SERVER_PORT+2),
+      '-p', str(_DEFAULT_SERVER_PORT+3),
+      '-p', str(_DEFAULT_SERVER_PORT+4),
+      '-p', str(_DEFAULT_SERVER_PORT+5),
+      '-p', str(_DEFAULT_SERVER_PORT+6),
+      '--net=host',
+    ]
+  else:
+    port_args = ['-p', str(_DEFAULT_SERVER_PORT)]
+
   docker_cmdline = docker_run_cmdline(cmdline,
                                       image=docker_image,
                                       cwd=language.server_cwd,
                                       environ=environ,
-                                      docker_args=['-p', str(_DEFAULT_SERVER_PORT),
-                                                   '--name', container_name])
-
+                                      docker_args=port_args +
+                                        ['--name', container_name])
   server_job = jobset.JobSpec(
           cmdline=docker_cmdline,
           environ=environ,
@@ -729,7 +797,12 @@
                   default=False,
                   action='store_const',
                   const=True,
-                  help='Enable HTTP/2 interop tests')
+                  help='Enable HTTP/2 client edge case testing. (Bad client, good server)')
+argp.add_argument('--http2_badserver_interop',
+                  default=False,
+                  action='store_const',
+                  const=True,
+                  help='Enable HTTP/2 server edge case testing. (Good client, bad server)')
 
 args = argp.parse_args()
 
@@ -756,6 +829,7 @@
                       for x in args.language))
 
 http2Interop = Http2Client() if args.http2_interop else None
+http2InteropServer = Http2Server() if args.http2_badserver_interop else None
 
 docker_images={}
 if args.use_docker:
@@ -765,6 +839,9 @@
   if args.http2_interop:
     languages_to_build.add(http2Interop)
 
+  if args.http2_badserver_interop:
+    languages_to_build.add(http2InteropServer)
+
   build_jobs = []
   for l in languages_to_build:
     job = build_interop_image_jobspec(l)
@@ -796,6 +873,14 @@
     server_jobs[lang] = job
     server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
 
+  if args.http2_badserver_interop:
+    # launch a HTTP2 server emulator that creates edge cases
+    lang = str(http2InteropServer)
+    spec = server_jobspec(http2InteropServer, docker_images.get(lang))
+    job = dockerjob.DockerJob(spec)
+    server_jobs[lang] = job
+    server_addresses[lang] = ('localhost', _DEFAULT_SERVER_PORT)
+
   jobs = []
   if args.cloud_to_prod:
     for server_host_name in args.prod_servers:
@@ -839,17 +924,18 @@
     skip_server = []  # test cases unimplemented by server
     if server_language:
       skip_server = server_language.unimplemented_test_cases_server()
-    for language in languages:
-      for test_case in _TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          if not test_case in skip_server:
-            test_job = cloud_to_cloud_jobspec(language,
-                                              test_case,
-                                              server_name,
-                                              server_host,
-                                              server_port,
-                                              docker_image=docker_images.get(str(language)))
-            jobs.append(test_job)
+    if not args.http2_badserver_interop:
+      for language in languages:
+        for test_case in _TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            if not test_case in skip_server:
+              test_job = cloud_to_cloud_jobspec(language,
+                                                test_case,
+                                                server_name,
+                                                server_host,
+                                                server_port,
+                                                docker_image=docker_images.get(str(language)))
+              jobs.append(test_job)
 
     if args.http2_interop:
       for test_case in _HTTP2_TEST_CASES:
@@ -864,6 +950,17 @@
                                           docker_image=docker_images.get(str(http2Interop)))
         jobs.append(test_job)
 
+    if args.http2_badserver_interop:
+      for language in languages:
+        for test_case in _HTTP2_BADSERVER_TEST_CASES:
+          test_job = cloud_to_cloud_jobspec(language,
+                                            test_case,
+                                            server_name,
+                                            server_host,
+                                            server_port,
+                                            docker_image=docker_images.get(str(language)))
+          jobs.append(test_job)
+
   if not jobs:
     print('No jobs to run.')
     for image in docker_images.itervalues():
diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py
index 69ccff8..12b5e01 100755
--- a/tools/run_tests/run_performance_tests.py
+++ b/tools/run_tests/run_performance_tests.py
@@ -35,21 +35,21 @@
 import argparse
 import collections
 import itertools
-import jobset
 import json
 import multiprocessing
 import os
-import performance.scenario_config as scenario_config
 import pipes
 import re
-import report_utils
 import subprocess
 import sys
 import tempfile
 import time
 import traceback
 import uuid
-import report_utils
+
+import performance.scenario_config as scenario_config
+import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
 
 
 _ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
@@ -58,8 +58,6 @@
 
 _REMOTE_HOST_USERNAME = 'jenkins'
 
-_PERF_REPORT_OUTPUT_DIR = 'perf_reports'
-
 
 class QpsWorkerJob:
   """Encapsulates a qps worker server job."""
@@ -113,7 +111,7 @@
 
 
 def create_scenario_jobspec(scenario_json, workers, remote_host=None,
-                            bq_result_table=None):
+                            bq_result_table=None, server_cpu_load=0):
   """Runs one scenario using QPS driver."""
   # setting QPS_WORKERS env variable here makes sure it works with SSH too.
   cmd = 'QPS_WORKERS="%s" ' % ','.join(workers)
@@ -121,7 +119,9 @@
     cmd += 'BQ_RESULT_TABLE="%s" ' % bq_result_table
   cmd += 'tools/run_tests/performance/run_qps_driver.sh '
   cmd += '--scenarios_json=%s ' % pipes.quote(json.dumps({'scenarios': [scenario_json]}))
-  cmd += '--scenario_result_file=scenario_result.json'
+  cmd += '--scenario_result_file=scenario_result.json '
+  if server_cpu_load != 0:
+      cmd += '--search_param=offered_load --initial_search_value=1000 --targeted_cpu_load=%d --stride=500 --error_tolerance=0.01' % server_cpu_load
   if remote_host:
     user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, remote_host)
     cmd = 'ssh %s "cd ~/performance_workspace/grpc/ && "%s' % (user_at_host, pipes.quote(cmd))
@@ -129,7 +129,7 @@
   return jobset.JobSpec(
       cmdline=[cmd],
       shortname='qps_json_driver.%s' % scenario_json['name'],
-      timeout_seconds=3*60,
+      timeout_seconds=12*60,
       shell=True,
       verbose_success=True)
 
@@ -300,11 +300,11 @@
     user_at_host = "%s@%s" % (_REMOTE_HOST_USERNAME, worker_host)
     cmd = "USER_AT_HOST=%s OUTPUT_FILENAME=%s OUTPUT_DIR=%s PERF_BASE_NAME=%s\
          tools/run_tests/performance/process_remote_perf_flamegraphs.sh" \
-          % (user_at_host, output_filename, _PERF_REPORT_OUTPUT_DIR, perf_base_name)
+          % (user_at_host, output_filename, args.flame_graph_reports, perf_base_name)
   else:
     cmd = "OUTPUT_FILENAME=%s OUTPUT_DIR=%s PERF_BASE_NAME=%s\
           tools/run_tests/performance/process_local_perf_flamegraphs.sh" \
-          % (output_filename, _PERF_REPORT_OUTPUT_DIR, perf_base_name)
+          % (output_filename, args.flame_graph_reports, perf_base_name)
 
   return jobset.JobSpec(cmdline=cmd,
                         timeout_seconds=3*60,
@@ -318,7 +318,7 @@
 
 def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
                      category='all', bq_result_table=None,
-                     netperf=False, netperf_hosts=[]):
+                     netperf=False, netperf_hosts=[], server_cpu_load=0):
   """Create jobspecs for scenarios to run."""
   all_workers = [worker
                  for workers in workers_by_lang.values()
@@ -379,7 +379,8 @@
               create_scenario_jobspec(scenario_json,
                                       [w.host_and_port for w in workers],
                                       remote_host=remote_host,
-                                      bq_result_table=bq_result_table),
+                                      bq_result_table=bq_result_table,
+                                      server_cpu_load=server_cpu_load),
               workers,
               scenario_json['name'])
           scenarios.append(scenario)
@@ -461,6 +462,9 @@
                   action='store_const',
                   const=True,
                   help='Run netperf benchmark as one of the scenarios.')
+argp.add_argument('--server_cpu_load',
+                  default=0, type=int,
+                  help='Select a targeted server cpu load to run. 0 means ignore this flag')
 argp.add_argument('-x', '--xml_report', default='report.xml', type=str,
                   help='Name of XML report file to generate.')
 argp.add_argument('--perf_args',
@@ -469,7 +473,7 @@
                         'with the arguments to perf specified here. '
                         '".svg" flame graph profiles will be '
                         'created for each Qps Worker on each scenario. '
-                        'Files will output to "<repo_root>/perf_reports" '
+                        'Files will output to "<repo_root>/<args.flame_graph_reports>" '
                         'directory. Output files from running the worker '
                         'under perf are saved in the repo root where its ran. '
                         'Note that the perf "-g" flag is necessary for '
@@ -489,7 +493,8 @@
                   help=('Turn flame graph generation off. '
                         'May be useful if "perf_args" arguments do not make sense for '
                         'generating flamegraphs (e.g., "--perf_args=stat ...")'))
-
+argp.add_argument('-f', '--flame_graph_reports', default='perf_reports', type=str,
+                  help='Name of directory to output flame graph profiles to, if any are created.')
 
 args = argp.parse_args()
 
@@ -522,8 +527,9 @@
 
 perf_cmd = None
 if args.perf_args:
+  print('Running workers under perf profiler')
   # Expect /usr/bin/perf to be installed here, as is usual
-  perf_cmd = ['/usr/bin/perf'] 
+  perf_cmd = ['/usr/bin/perf']
   perf_cmd.extend(re.split('\s+', args.perf_args))
 
 qpsworker_jobs = create_qpsworkers(languages, args.remote_worker_host, perf_cmd=perf_cmd)
@@ -540,7 +546,8 @@
                            category=args.category,
                            bq_result_table=args.bq_result_table,
                            netperf=args.netperf,
-                           netperf_hosts=args.remote_worker_host)
+                           netperf_hosts=args.remote_worker_host,
+                           server_cpu_load=args.server_cpu_load)
 
 if not scenarios:
   raise Exception('No scenarios to run')
@@ -582,7 +589,7 @@
 # 'profile_output_files' will only have names for scenarios that passed
 if perf_cmd and not args.skip_generate_flamegraphs:
   # write the index fil to the output dir, with all profiles from all scenarios/workers
-  report_utils.render_perf_profiling_results('%s/index.html' % _PERF_REPORT_OUTPUT_DIR, profile_output_files)
+  report_utils.render_perf_profiling_results('%s/index.html' % args.flame_graph_reports, profile_output_files)
 
 if total_scenario_failures > 0 or qps_workers_killed > 0:
   print('%s scenarios failed and %s qps worker jobs killed' % (total_scenario_failures, qps_workers_killed))
diff --git a/tools/run_tests/run_stress_tests.py b/tools/run_tests/run_stress_tests.py
index de4a228..a94a615 100755
--- a/tools/run_tests/run_stress_tests.py
+++ b/tools/run_tests/run_stress_tests.py
@@ -33,9 +33,7 @@
 
 import argparse
 import atexit
-import dockerjob
 import itertools
-import jobset
 import json
 import multiprocessing
 import os
@@ -46,6 +44,9 @@
 import time
 import uuid
 
+import python_utils.dockerjob as dockerjob
+import python_utils.jobset as jobset
+
 # Docker doesn't clean up after itself, so we do it on exit.
 atexit.register(lambda: subprocess.call(['stty', 'echo']))
 
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index c49ee4a..5aae343 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -54,9 +54,9 @@
 from six.moves import urllib
 import uuid
 
-import jobset
-import report_utils
-import watch_dirs
+import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
+import python_utils.watch_dirs as watch_dirs
 
 
 _ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
@@ -116,7 +116,7 @@
 def get_c_tests(travis, test_lang) :
   out = []
   platforms_str = 'ci_platforms' if travis else 'platforms'
-  with open('tools/run_tests/tests.json') as f:
+  with open('tools/run_tests/generated/tests.json') as f:
     js = json.load(f)
     return [tgt
             for tgt in js
@@ -300,7 +300,7 @@
 
   def pre_build_steps(self):
     if self.platform == 'windows':
-      return [['tools\\run_tests\\pre_build_c.bat']]
+      return [['tools\\run_tests\\helper_scripts\\pre_build_c.bat']]
     else:
       return []
 
@@ -311,7 +311,7 @@
     if self.platform == 'windows':
       return []
     else:
-      return [['tools/run_tests/post_tests_c.sh']]
+      return [['tools/run_tests/helper_scripts/post_tests_c.sh']]
 
   def makefile_name(self):
     return 'Makefile'
@@ -371,28 +371,43 @@
   def configure(self, config, args):
     self.config = config
     self.args = args
+    # Note: electron ABI only depends on major and minor version, so that's all
+    # we should specify in the compiler argument
     _check_compiler(self.args.compiler, ['default', 'node0.12',
                                          'node4', 'node5', 'node6',
-                                         'node7'])
+                                         'node7', 'electron1.3'])
     if self.args.compiler == 'default':
+      self.runtime = 'node'
       self.node_version = '4'
     else:
-      # Take off the word "node"
-      self.node_version = self.args.compiler[4:]
+      if self.args.compiler.startswith('electron'):
+        self.runtime = 'electron'
+        self.node_version = self.args.compiler[8:]
+      else:
+        self.runtime = 'node'
+        # Take off the word "node"
+        self.node_version = self.args.compiler[4:]
 
   def test_specs(self):
     if self.platform == 'windows':
-      return [self.config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
+      return [self.config.job_spec(['tools\\run_tests\\helper_scripts\\run_node.bat'])]
     else:
-      return [self.config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
+      run_script = 'run_node'
+      if self.runtime == 'electron':
+        run_script += '_electron'
+      return [self.config.job_spec(['tools/run_tests/helper_scripts/{}.sh'.format(run_script),
+                                    self.node_version],
                                    None,
                                    environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
     if self.platform == 'windows':
-      return [['tools\\run_tests\\pre_build_node.bat']]
+      return [['tools\\run_tests\\helper_scripts\\pre_build_node.bat']]
     else:
-      return [['tools/run_tests/pre_build_node.sh', self.node_version]]
+      build_script = 'pre_build_node'
+      if self.runtime == 'electron':
+        build_script += '_electron'
+      return [['tools/run_tests/helper_scripts/{}.sh'.format(build_script), self.node_version]]
 
   def make_targets(self):
     return []
@@ -402,9 +417,14 @@
 
   def build_steps(self):
     if self.platform == 'windows':
-      return [['tools\\run_tests\\build_node.bat']]
+      return [['tools\\run_tests\\helper_scripts\\build_node.bat']]
     else:
-      return [['tools/run_tests/build_node.sh', self.node_version]]
+      build_script = 'build_node'
+      if self.runtime == 'electron':
+        build_script += '_electron'
+        # building for electron requires a patch version
+        self.node_version += '.0'
+      return [['tools/run_tests/helper_scripts/{}.sh'.format(build_script), self.node_version]]
 
   def post_tests_steps(self):
     return []
@@ -427,7 +447,7 @@
     _check_compiler(self.args.compiler, ['default'])
 
   def test_specs(self):
-    return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
+    return [self.config.job_spec(['src/php/bin/run_tests.sh'],
                                   environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
@@ -440,10 +460,10 @@
     return []
 
   def build_steps(self):
-    return [['tools/run_tests/build_php.sh']]
+    return [['tools/run_tests/helper_scripts/build_php.sh']]
 
   def post_tests_steps(self):
-    return [['tools/run_tests/post_tests_php.sh']]
+    return [['tools/run_tests/helper_scripts/post_tests_php.sh']]
 
   def makefile_name(self):
     return 'Makefile'
@@ -463,7 +483,7 @@
     _check_compiler(self.args.compiler, ['default'])
 
   def test_specs(self):
-    return [self.config.job_spec(['src/php/bin/run_tests.sh'], None,
+    return [self.config.job_spec(['src/php/bin/run_tests.sh'],
                                   environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
@@ -476,10 +496,10 @@
     return []
 
   def build_steps(self):
-    return [['tools/run_tests/build_php.sh']]
+    return [['tools/run_tests/helper_scripts/build_php.sh']]
 
   def post_tests_steps(self):
-    return [['tools/run_tests/post_tests_php.sh']]
+    return [['tools/run_tests/helper_scripts/post_tests_php.sh']]
 
   def makefile_name(self):
     return 'Makefile'
@@ -548,18 +568,18 @@
 
     if os.name == 'nt':
       shell = ['bash']
-      builder = [os.path.abspath('tools/run_tests/build_python_msys2.sh')]
+      builder = [os.path.abspath('tools/run_tests/helper_scripts/build_python_msys2.sh')]
       builder_prefix_arguments = ['MINGW{}'.format(bits)]
       venv_relative_python = ['Scripts/python.exe']
       toolchain = ['mingw32']
     else:
       shell = []
-      builder = [os.path.abspath('tools/run_tests/build_python.sh')]
+      builder = [os.path.abspath('tools/run_tests/helper_scripts/build_python.sh')]
       builder_prefix_arguments = []
       venv_relative_python = ['bin/python']
       toolchain = ['unix']
 
-    runner = [os.path.abspath('tools/run_tests/run_python.sh')]
+    runner = [os.path.abspath('tools/run_tests/helper_scripts/run_python.sh')]
     config_vars = _PythonConfigVars(shell, builder, builder_prefix_arguments,
                               venv_relative_python, toolchain, runner)
     python27_config = _python_config_generator(name='py27', major='2',
@@ -611,12 +631,12 @@
     _check_compiler(self.args.compiler, ['default'])
 
   def test_specs(self):
-    return [self.config.job_spec(['tools/run_tests/run_ruby.sh'],
+    return [self.config.job_spec(['tools/run_tests/helper_scripts/run_ruby.sh'],
                                  timeout_seconds=10*60,
                                  environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
-    return [['tools/run_tests/pre_build_ruby.sh']]
+    return [['tools/run_tests/helper_scripts/pre_build_ruby.sh']]
 
   def make_targets(self):
     return []
@@ -625,10 +645,10 @@
     return []
 
   def build_steps(self):
-    return [['tools/run_tests/build_ruby.sh']]
+    return [['tools/run_tests/helper_scripts/build_ruby.sh']]
 
   def post_tests_steps(self):
-    return [['tools/run_tests/post_tests_ruby.sh']]
+    return [['tools/run_tests/helper_scripts/post_tests_ruby.sh']]
 
   def makefile_name(self):
     return 'Makefile'
@@ -702,7 +722,6 @@
         for test in tests_by_assembly[assembly]:
           cmdline = runtime_cmd + [assembly_file, '--test=%s' % test] + nunit_args
           specs.append(self.config.job_spec(cmdline,
-                                            None,
                                             shortname='csharp.%s' % test,
                                             environ=_FORCE_ENVIRON_FOR_WRAPPERS))
       else:
@@ -720,7 +739,6 @@
         # to prevent problems with registering the profiler.
         run_exclusive = 1000000
         specs.append(self.config.job_spec(cmdline,
-                                          None,
                                           shortname='csharp.coverage.%s' % assembly,
                                           cpu_cost=run_exclusive,
                                           environ=_FORCE_ENVIRON_FOR_WRAPPERS))
@@ -728,9 +746,9 @@
 
   def pre_build_steps(self):
     if self.platform == 'windows':
-      return [['tools\\run_tests\\pre_build_csharp.bat']]
+      return [['tools\\run_tests\\helper_scripts\\pre_build_csharp.bat']]
     else:
-      return [['tools/run_tests/pre_build_csharp.sh']]
+      return [['tools/run_tests/helper_scripts/pre_build_csharp.sh']]
 
   def make_targets(self):
     return ['grpc_csharp_ext']
@@ -741,22 +759,22 @@
   def build_steps(self):
     if self.args.compiler == 'coreclr':
       if self.platform == 'windows':
-        return [['tools\\run_tests\\build_csharp_coreclr.bat']]
+        return [['tools\\run_tests\\helper_scripts\\build_csharp_coreclr.bat']]
       else:
-        return [['tools/run_tests/build_csharp_coreclr.sh']]
+        return [['tools/run_tests/helper_scripts/build_csharp_coreclr.sh']]
     else:
       if self.platform == 'windows':
         return [[_windows_build_bat(self.args.compiler),
                  'src/csharp/Grpc.sln',
                  '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
       else:
-        return [['tools/run_tests/build_csharp.sh']]
+        return [['tools/run_tests/helper_scripts/build_csharp.sh']]
 
   def post_tests_steps(self):
     if self.platform == 'windows':
-      return [['tools\\run_tests\\post_tests_csharp.bat']]
+      return [['tools\\run_tests\\helper_scripts\\post_tests_csharp.bat']]
     else:
-      return [['tools/run_tests/post_tests_csharp.sh']]
+      return [['tools/run_tests/helper_scripts/post_tests_csharp.sh']]
 
   def makefile_name(self):
     return 'Makefile'
@@ -779,7 +797,7 @@
   def test_specs(self):
     return [
         self.config.job_spec(['src/objective-c/tests/run_tests.sh'],
-                              timeout_seconds=None,
+                              timeout_seconds=60*60,
                               shortname='objc-tests',
                               environ=_FORCE_ENVIRON_FOR_WRAPPERS),
         self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
@@ -823,8 +841,12 @@
   def test_specs(self):
     import yaml
     with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
+      environ={'TEST': 'true'}
+      if _is_use_docker_child():
+        environ['CLANG_FORMAT_SKIP_DOCKER'] = 'true'
       return [self.config.job_spec(cmd['script'].split(),
-                                   timeout_seconds=None, environ={'TEST': 'true'},
+                                   timeout_seconds=30*60,
+                                   environ=environ,
                                    cpu_cost=cmd.get('cpu_cost', 1))
               for cmd in yaml.load(f)]
 
@@ -875,9 +897,9 @@
 
   def pre_build_steps(self):
     if self.platform == 'windows':
-      return [['tools\\run_tests\\pre_build_node.bat']]
+      return [['tools\\run_tests\\helper_scripts\\pre_build_node.bat']]
     else:
-      return [['tools/run_tests/pre_build_node.sh', self.node_version]]
+      return [['tools/run_tests/helper_scripts/pre_build_node.sh', self.node_version]]
 
   def make_targets(self):
     return []
@@ -901,7 +923,7 @@
     return 'node_express'
 
 # different configurations we can run under
-with open('tools/run_tests/configs.json') as f:
+with open('tools/run_tests/generated/configs.json') as f:
   _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
 
 
@@ -1075,6 +1097,7 @@
                            'vs2010', 'vs2013', 'vs2015',
                            'python2.7', 'python3.4', 'python3.5', 'python3.6', 'pypy', 'pypy3',
                            'node0.12', 'node4', 'node5', 'node6', 'node7',
+                           'electron1.3',
                            'coreclr'],
                   default='default',
                   help='Selects compiler to use. Allowed values depend on the platform and language.')
@@ -1097,6 +1120,12 @@
         help='Generates a JUnit-compatible XML report')
 argp.add_argument('--report_suite_name', default='tests', type=str,
         help='Test suite name to use in generated JUnit XML report')
+argp.add_argument('--quiet_success',
+                  default=False,
+                  action='store_const',
+                  const=True,
+                  help='Dont print anything when a test passes. Passing tests also will not be reported in XML report. ' +
+                       'Useful when running many iterations of each test (argument -n).')
 argp.add_argument('--force_default_poller', default=False, action='store_const', const=True,
                   help='Dont try to iterate over many polling strategies when they exist')
 args = argp.parse_args()
@@ -1296,7 +1325,7 @@
     running = False
   if running:
     current_version = int(subprocess.check_output(
-        [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
+        [sys.executable, os.path.abspath('tools/run_tests/python_utils/port_server.py'),
          'dump_version']))
     print('my port server is version %d' % current_version)
     running = (version >= current_version)
@@ -1308,7 +1337,7 @@
     fd, logfile = tempfile.mkstemp()
     os.close(fd)
     print('starting port_server, with log file %s' % logfile)
-    args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
+    args = [sys.executable, os.path.abspath('tools/run_tests/python_utils/port_server.py'),
             '-p', '%d' % port_server_port, '-l', logfile]
     env = dict(os.environ)
     env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
@@ -1414,7 +1443,7 @@
     return []
 
   # start antagonists
-  antagonists = [subprocess.Popen(['tools/run_tests/antagonist.py'])
+  antagonists = [subprocess.Popen(['tools/run_tests/python_utils/antagonist.py'])
                  for _ in range(0, args.antagonists)]
   port_server_port = 32766
   _start_port_server(port_server_port)
@@ -1444,20 +1473,24 @@
                      else itertools.repeat(massaged_one_run, runs_per_test))
     all_runs = itertools.chain.from_iterable(runs_sequence)
 
+    if args.quiet_success:
+      jobset.message('START', 'Running tests quietly, only failing tests will be reported', do_newline=True)
     num_test_failures, resultset = jobset.run(
         all_runs, check_cancelled, newline_on_success=newline_on_success,
         travis=args.travis, infinite_runs=infinite_runs, maxjobs=args.jobs,
         stop_on_failure=args.stop_on_failure,
-        add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port})
+        add_env={'GRPC_TEST_PORT_SERVER': 'localhost:%d' % port_server_port},
+        quiet_success=args.quiet_success)
     if resultset:
       for k, v in sorted(resultset.items()):
         num_runs, num_failures = _calculate_num_runs_failures(v)
-        if num_failures == num_runs:  # what about infinite_runs???
-          jobset.message('FAILED', k, do_newline=True)
-        elif num_failures > 0:
-          jobset.message(
-              'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
-              do_newline=True)
+        if num_failures > 0:
+          if num_failures == num_runs:  # what about infinite_runs???
+            jobset.message('FAILED', k, do_newline=True)
+          else:
+            jobset.message(
+                'FLAKE', '%s [%d/%d runs flaked]' % (k, num_failures, num_runs),
+                do_newline=True)
   finally:
     for antagonist in antagonists:
       antagonist.kill()
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 989bc7e..8f70a6d 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -31,12 +31,13 @@
 """Run test matrix."""
 
 import argparse
-import jobset
 import multiprocessing
 import os
-import report_utils
 import sys
-from filter_pull_request_tests import filter_tests
+
+import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
+from python_utils.filter_pull_request_tests import filter_tests
 
 _ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
 os.chdir(_ROOT)
@@ -69,7 +70,7 @@
     workspace_name = 'workspace_%s' % name
   env = {'WORKSPACE_NAME': workspace_name}
   test_job = jobset.JobSpec(
-          cmdline=['tools/run_tests/run_tests_in_workspace.sh',
+          cmdline=['tools/run_tests/helper_scripts/run_tests_in_workspace.sh',
                    '-t',
                    '-j', str(inner_jobs),
                    '-x', '../report_%s.xml' % name,
@@ -230,6 +231,15 @@
                               labels=['portability'],
                               extra_args=extra_args,
                               inner_jobs=inner_jobs)
+
+  test_jobs += _generate_jobs(languages=['node'],
+                              configs=['dbg'],
+                              platforms=['linux'],
+                              arch='default',
+                              compiler='electron1.3',
+                              labels=['portability'],
+                              extra_args=extra_args,
+                              inner_jobs=inner_jobs)
   return test_jobs
 
 
@@ -242,6 +252,17 @@
   return sorted(all_labels)
 
 
+def _runs_per_test_type(arg_str):
+  """Auxiliary function to parse the "runs_per_test" flag."""
+  try:
+    n = int(arg_str)
+    if n <= 0: raise ValueError
+    return n
+  except:
+    msg = '\'{}\' is not a positive integer'.format(arg_str)
+    raise argparse.ArgumentTypeError(msg)
+
+
 if __name__ == "__main__":
   argp = argparse.ArgumentParser(description='Run a matrix of run_tests.py tests.')
   argp.add_argument('-j', '--jobs',
@@ -253,6 +274,11 @@
                     nargs='+',
                     default=[],
                     help='Filter targets to run by label with AND semantics.')
+  argp.add_argument('--exclude',
+                    choices=_allowed_labels(),
+                    nargs='+',
+                    default=[],
+                    help='Exclude targets with any of given labels.')
   argp.add_argument('--build_only',
                     default=False,
                     action='store_const',
@@ -269,7 +295,7 @@
                     default=False,
                     action='store_const',
                     const=True,
-                    help='Filters out tests irrelavant to pull request changes.')
+                    help='Filters out tests irrelevant to pull request changes.')
   argp.add_argument('--base_branch',
                     default='origin/master',
                     type=str,
@@ -278,6 +304,9 @@
                     default=_DEFAULT_INNER_JOBS,
                     type=int,
                     help='Number of jobs in each run_tests.py instance')
+  argp.add_argument('-n', '--runs_per_test', default=1, type=_runs_per_test_type,
+                    help='How many times to run each tests. >1 runs implies ' +
+                    'omitting passing test from the output & reports.')
   args = argp.parse_args()
 
   extra_args = []
@@ -285,6 +314,10 @@
     extra_args.append('--build_only')
   if args.force_default_poller:
     extra_args.append('--force_default_poller')
+  if args.runs_per_test > 1:
+    extra_args.append('-n')
+    extra_args.append('%s' % args.runs_per_test)
+    extra_args.append('--quiet_success')
 
   all_jobs = _create_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs) + \
              _create_portability_test_jobs(extra_args=extra_args, inner_jobs=args.inner_jobs)
@@ -292,7 +325,8 @@
   jobs = []
   for job in all_jobs:
     if not args.filter or all(filter in job.labels for filter in args.filter):
-      jobs.append(job)
+      if not any(exclude_label in job.labels for exclude_label in args.exclude):
+        jobs.append(job)
 
   if not jobs:
     jobset.message('FAILED', 'No test suites match given criteria.',
diff --git a/tools/run_tests/sanity/check_sources_and_headers.py b/tools/run_tests/sanity/check_sources_and_headers.py
index b733ba1..a86db02 100755
--- a/tools/run_tests/sanity/check_sources_and_headers.py
+++ b/tools/run_tests/sanity/check_sources_and_headers.py
@@ -34,7 +34,7 @@
 import sys
 
 root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
-with open(os.path.join(root, 'tools', 'run_tests', 'sources_and_headers.json')) as f:
+with open(os.path.join(root, 'tools', 'run_tests', 'generated', 'sources_and_headers.json')) as f:
   js = json.loads(f.read())
 
 re_inc1 = re.compile(r'^#\s*include\s*"([^"]*)"')
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index be12f96..61e8185 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -41,13 +41,14 @@
 
 git submodule | awk '{ print $1 }' | sort > $submodules
 cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- c880e42ba1c8032d4cdde2aba0541d8a9d9fa2e9 third_party/boringssl (version_for_cocoapods_2.0-100-gc880e42)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
  44c25c892a6229b20db7cd9dc05584ea865896de third_party/benchmark (v0.1.0-343-g44c25c8)
+ c880e42ba1c8032d4cdde2aba0541d8a9d9fa2e9 third_party/boringssl (c880e42)
+ 886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
+ 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
  c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- a428e42072765993ff674fda72863c9f1aa2d268 third_party/protobuf (v3.1.0)
+ a428e42072765993ff674fda72863c9f1aa2d268 third_party/protobuf (v3.1.0-alpha-1)
+ bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift (bcad917)
  50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
- bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift
 EOF
 
 diff -u $submodules $want_submodules
diff --git a/tools/run_tests/sanity/check_test_filtering.py b/tools/run_tests/sanity/check_test_filtering.py
index b522cde..290a6e2 100755
--- a/tools/run_tests/sanity/check_test_filtering.py
+++ b/tools/run_tests/sanity/check_test_filtering.py
@@ -38,7 +38,7 @@
 # hack import paths to pick up extra code
 sys.path.insert(0, os.path.abspath('tools/run_tests/'))
 from run_tests_matrix import _create_test_jobs, _create_portability_test_jobs
-import filter_pull_request_tests
+import python_utils.filter_pull_request_tests as filter_pull_request_tests
 
 _LIST_OF_LANGUAGE_LABELS = ['c', 'c++', 'csharp', 'node', 'objc', 'php', 'php7', 'python', 'ruby']
 _LIST_OF_PLATFORM_LABELS = ['linux', 'macos', 'windows']
diff --git a/tools/run_tests/sanity/core_banned_functions.py b/tools/run_tests/sanity/core_banned_functions.py
new file mode 100755
index 0000000..afac10b
--- /dev/null
+++ b/tools/run_tests/sanity/core_banned_functions.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import sys
+
+os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
+
+# map of banned function signature to whitelist
+BANNED_EXCEPT = {
+    'grpc_resource_quota_ref(': ['src/core/lib/iomgr/resource_quota.c'],
+    'grpc_resource_quota_unref(': ['src/core/lib/iomgr/resource_quota.c'],
+    'grpc_slice_buffer_destroy(': ['src/core/lib/slice/slice_buffer.c'],
+    'grpc_slice_buffer_reset_and_unref(': ['src/core/lib/slice/slice_buffer.c'],
+    'grpc_slice_ref(': ['src/core/lib/slice/slice.c'],
+    'grpc_slice_unref(': ['src/core/lib/slice/slice.c'],
+}
+
+errors = 0
+for root, dirs, files in os.walk('src/core'):
+  for filename in files:
+    path = os.path.join(root, filename)
+    if os.path.splitext(path)[1] != '.c': continue
+    with open(path) as f:
+      text = f.read()
+    for banned, exceptions in BANNED_EXCEPT.items():
+      if path in exceptions: continue
+      if banned in text:
+        print 'Illegal use of "%s" in %s' % (banned, path)
+        errors += 1
+
+assert errors == 0
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
index 32e62dd..3781916 100644
--- a/tools/run_tests/sanity/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -3,6 +3,7 @@
 - script: tools/run_tests/sanity/check_sources_and_headers.py
 - script: tools/run_tests/sanity/check_submodules.sh
 - script: tools/run_tests/sanity/check_test_filtering.py
+- script: tools/run_tests/sanity/core_banned_functions.py
 - script: tools/buildgen/generate_projects.sh -j 3
   cpu_cost: 3
 - script: tools/distrib/check_copyright.py
@@ -12,3 +13,4 @@
 - script: tools/distrib/check_nanopb_output.sh
 - script: tools/distrib/check_include_guards.py
 - script: tools/distrib/python/check_grpcio_tools.py
+
diff --git a/tools/run_tests/task_runner.py b/tools/run_tests/task_runner.py
index 2e3fa44..fdc4668 100755
--- a/tools/run_tests/task_runner.py
+++ b/tools/run_tests/task_runner.py
@@ -33,14 +33,13 @@
 from __future__ import print_function
 
 import argparse
-import atexit
-import jobset
 import multiprocessing
 import sys
 
-import artifact_targets
-import distribtest_targets
-import package_targets
+import artifacts.artifact_targets as artifact_targets
+import artifacts.distribtest_targets as distribtest_targets
+import artifacts.package_targets as package_targets
+import python_utils.jobset as jobset
 
 _TARGETS = []
 _TARGETS += artifact_targets.targets()
diff --git a/vsprojects/README.md b/vsprojects/README.md
index 7af69c2..afd6430 100644
--- a/vsprojects/README.md
+++ b/vsprojects/README.md
@@ -2,7 +2,7 @@
 
 #Supported Visual Studio versions
 
-Currently supported versions are Visual Studio 2013 (our primary focus) and 2010.
+Currently supported versions are Visual Studio 2013 (our primary focus).
 
 #Building
 We are using [NuGet](http://www.nuget.org) to pull zlib and openssl dependencies.
diff --git a/vsprojects/build_vs2010.bat b/vsprojects/build_vs2010.bat
deleted file mode 100644
index d951295..0000000
--- a/vsprojects/build_vs2010.bat
+++ /dev/null
@@ -1,39 +0,0 @@
-@rem Copyright 2016, Google Inc.
-@rem All rights reserved.
-@rem
-@rem Redistribution and use in source and binary forms, with or without
-@rem modification, are permitted provided that the following conditions are
-@rem met:
-@rem
-@rem     * Redistributions of source code must retain the above copyright
-@rem notice, this list of conditions and the following disclaimer.
-@rem     * Redistributions in binary form must reproduce the above
-@rem copyright notice, this list of conditions and the following disclaimer
-@rem in the documentation and/or other materials provided with the
-@rem distribution.
-@rem     * Neither the name of Google Inc. nor the names of its
-@rem contributors may be used to endorse or promote products derived from
-@rem this software without specific prior written permission.
-@rem
-@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-@rem Convenience wrapper that runs specified gRPC target using msbuild
-@rem Usage: build_vs2010.bat TARGET_NAME
-
-setlocal
-@rem Set VS variables (uses Visual Studio 2010)
-@call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
-
-msbuild %*
-exit /b %ERRORLEVEL%
-endlocal
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index d08a47a..f484f29 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1202,6 +1202,28 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_profile_client", "vcxproj\test\memory_profile_client\memory_profile_client.vcxproj", "{98C01DBE-EFFE-6988-0762-829DC88F0EB4}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "memory_profile_server", "vcxproj\test\memory_profile_server\memory_profile_server.vcxproj", "{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "message_compress_test", "vcxproj\test\message_compress_test\message_compress_test.vcxproj", "{07170557-CCB0-D23C-8018-C2909D115DF9}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -3377,6 +3399,38 @@
 		{DC76C089-0D55-DF19-7CCA-49DAE5D29E49}.Release-DLL|Win32.Build.0 = Release|Win32
 		{DC76C089-0D55-DF19-7CCA-49DAE5D29E49}.Release-DLL|x64.ActiveCfg = Release|x64
 		{DC76C089-0D55-DF19-7CCA-49DAE5D29E49}.Release-DLL|x64.Build.0 = Release|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug|Win32.ActiveCfg = Debug|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug|x64.ActiveCfg = Debug|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release|Win32.ActiveCfg = Release|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release|x64.ActiveCfg = Release|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug|Win32.Build.0 = Debug|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug|x64.Build.0 = Debug|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release|Win32.Build.0 = Release|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release|x64.Build.0 = Release|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Debug-DLL|x64.Build.0 = Debug|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release-DLL|Win32.Build.0 = Release|Win32
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release-DLL|x64.ActiveCfg = Release|x64
+		{98C01DBE-EFFE-6988-0762-829DC88F0EB4}.Release-DLL|x64.Build.0 = Release|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug|x64.ActiveCfg = Debug|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release|Win32.ActiveCfg = Release|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release|x64.ActiveCfg = Release|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug|Win32.Build.0 = Debug|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug|x64.Build.0 = Debug|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release|Win32.Build.0 = Release|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release|x64.Build.0 = Release|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Debug-DLL|x64.Build.0 = Debug|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release-DLL|Win32.Build.0 = Release|Win32
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release-DLL|x64.ActiveCfg = Release|x64
+		{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}.Release-DLL|x64.Build.0 = Release|x64
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Debug|Win32.ActiveCfg = Debug|Win32
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Debug|x64.ActiveCfg = Debug|x64
 		{07170557-CCB0-D23C-8018-C2909D115DF9}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/coapp/zlib/README.md b/vsprojects/coapp/zlib/README.md
index d62e903..e9a89c0 100644
--- a/vsprojects/coapp/zlib/README.md
+++ b/vsprojects/coapp/zlib/README.md
@@ -10,7 +10,7 @@
 * Visual Studio 2013
 * Visual Studio 2010 (you might need SP1 to prevent LNK1123 error)
 
-CoApp toolkit: http://downloads.coapp.org/files/CoApp.Tools.Powershell.msi
+CoApp toolkit: http://coapp.org/files/CoApp.Tools.Powershell.msi
 
 More details on installation: http://coapp.org/tutorials/installation.html
 
@@ -33,4 +33,4 @@
 * the symbols package (debug symbols)
 
 Later, you can push the package to NuGet.org repo.
-Attention: before pusing the resulting nuget package to public nuget repo, you have to be 100% sure it works correctly - thereÂ’s no way how to delete or update an already existing package.
\ No newline at end of file
+Attention: before pusing the resulting nuget package to public nuget repo, you have to be 100% sure it works correctly - there’s no way how to delete or update an already existing package.
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index 63be171..591d3b5 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -3,11 +3,6 @@
 # Visual Studio 2013
 VisualStudioVersion = 12.0.21005.1
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "boringssl", "vcxproj\.\boringssl\boringssl.vcxproj", "{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}"
-	ProjectSection(myProperties) = preProject
-        	lib = "True"
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gen_hpack_tables", "vcxproj\.\gen_hpack_tables\gen_hpack_tables.vcxproj", "{FCDEA4C7-7F26-05DB-D08F-A08F499026E6}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -56,14 +51,6 @@
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_reflection", "vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj", "{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}"
-	ProjectSection(myProperties) = preProject
-        	lib = "True"
-	EndProjectSection
-	ProjectSection(ProjectDependencies) = postProject
-		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB} = {C187A093-A0FE-489D-A40A-6E33DE0F9FEB}
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_unsecure", "vcxproj\.\grpc++_unsecure\grpc++_unsecure.vcxproj", "{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}"
 	ProjectSection(myProperties) = preProject
         	lib = "True"
@@ -161,11 +148,6 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "z", "vcxproj\.\z\z.vcxproj", "{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}"
-	ProjectSection(myProperties) = preProject
-        	lib = "True"
-	EndProjectSection
-EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -178,22 +160,6 @@
 		Release-DLL|x64 = Release-DLL|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug|Win32.ActiveCfg = Debug|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug|x64.ActiveCfg = Debug|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release|Win32.ActiveCfg = Release|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release|x64.ActiveCfg = Release|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug|Win32.Build.0 = Debug|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug|x64.Build.0 = Debug|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release|Win32.Build.0 = Release|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release|x64.Build.0 = Release|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Debug-DLL|x64.Build.0 = Debug|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release-DLL|Win32.Build.0 = Release|Win32
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release-DLL|x64.ActiveCfg = Release|x64
-		{9FD9A3EF-C4A3-8390-D8F4-6F86C22A58CE}.Release-DLL|x64.Build.0 = Release|x64
 		{FCDEA4C7-7F26-05DB-D08F-A08F499026E6}.Debug|Win32.ActiveCfg = Debug|Win32
 		{FCDEA4C7-7F26-05DB-D08F-A08F499026E6}.Debug|x64.ActiveCfg = Debug|x64
 		{FCDEA4C7-7F26-05DB-D08F-A08F499026E6}.Release|Win32.ActiveCfg = Release|Win32
@@ -306,22 +272,6 @@
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|Win32.Build.0 = Release-DLL|Win32
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|x64.ActiveCfg = Release-DLL|x64
 		{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}.Release-DLL|x64.Build.0 = Release-DLL|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug|Win32.ActiveCfg = Debug|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug|x64.ActiveCfg = Debug|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release|Win32.ActiveCfg = Release|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release|x64.ActiveCfg = Release|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug|Win32.Build.0 = Debug|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug|x64.Build.0 = Debug|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release|Win32.Build.0 = Release|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release|x64.Build.0 = Release|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Debug-DLL|x64.Build.0 = Debug|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release-DLL|Win32.Build.0 = Release|Win32
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release-DLL|x64.ActiveCfg = Release|x64
-		{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}.Release-DLL|x64.Build.0 = Release|x64
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Debug|Win32.ActiveCfg = Debug|Win32
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Debug|x64.ActiveCfg = Debug|x64
 		{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}.Release|Win32.ActiveCfg = Release|Win32
@@ -482,22 +432,6 @@
 		{E3110C46-A148-FF65-08FD-3324829BE7FE}.Release-DLL|Win32.Build.0 = Release|Win32
 		{E3110C46-A148-FF65-08FD-3324829BE7FE}.Release-DLL|x64.ActiveCfg = Release|x64
 		{E3110C46-A148-FF65-08FD-3324829BE7FE}.Release-DLL|x64.Build.0 = Release|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug|Win32.ActiveCfg = Debug|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug|x64.ActiveCfg = Debug|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release|Win32.ActiveCfg = Release|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release|x64.ActiveCfg = Release|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug|Win32.Build.0 = Debug|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug|x64.Build.0 = Debug|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release|Win32.Build.0 = Release|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release|x64.Build.0 = Release|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Debug-DLL|x64.Build.0 = Debug|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release-DLL|Win32.Build.0 = Release|Win32
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release-DLL|x64.ActiveCfg = Release|x64
-		{FBADE9E3-6A3F-36D3-D676-C1B808451DD7}.Release-DLL|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index f281db7..7dd0b85 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -331,6 +331,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index f359e4e..28766bf 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -333,6 +333,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
index d2305b2..5b05d09 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
@@ -178,6 +178,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
index d1aaba7..b1fa72a 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
@@ -126,6 +126,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 1511a2c..48fb761 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -331,6 +331,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index bed77b2..7ce21ad 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -318,6 +318,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 558b5b0..2550d1e 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -279,6 +279,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
@@ -305,6 +306,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
@@ -371,6 +374,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
@@ -494,6 +498,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index a40a1b5..642ace6 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -25,6 +25,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -684,6 +690,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -758,6 +767,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -956,6 +971,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h">
       <Filter>src\core\lib\slice</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h">
+      <Filter>src\core\lib\slice</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h">
       <Filter>src\core\lib\slice</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 2acdd32..15e3097 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -159,6 +159,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
@@ -198,6 +199,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
@@ -264,6 +267,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
@@ -343,6 +347,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 6c918f1..43b7eaa 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -82,6 +82,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -435,6 +441,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -548,6 +557,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -746,6 +761,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h">
       <Filter>src\core\lib\slice</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h">
+      <Filter>src\core\lib\slice</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h">
       <Filter>src\core\lib\slice</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 6611921..d1d3cb2 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -270,6 +270,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
@@ -295,6 +296,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\message_size_filter.h" />
@@ -361,6 +364,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
@@ -462,6 +466,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 466116e..7741c62 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -28,6 +28,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
@@ -600,6 +606,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -671,6 +680,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_factory.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker_registry.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
@@ -869,6 +884,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\percent_encoding.h">
       <Filter>src\core\lib\slice</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_internal.h">
+      <Filter>src\core\lib\slice</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\slice\slice_string_helpers.h">
       <Filter>src\core\lib\slice</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj b/vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj
new file mode 100644
index 0000000..c94c346
--- /dev/null
+++ b/vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{8008C126-4B35-5A76-A795-39DA13DA57F4}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>http2_client_main</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>http2_client_main</TargetName>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\interop\http2_client.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\test.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\test.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\http2_client.cc">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
+      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_config\grpc++_test_config.vcxproj">
+      <Project>{3F7D093D-11F9-C4BC-BEB7-18EB28E3F290}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj.filters b/vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj.filters
new file mode 100644
index 0000000..40e4191
--- /dev/null
+++ b/vsprojects/vcxproj/http2_client_main/http2_client_main.vcxproj.filters
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\empty.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\messages.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\test.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\http2_client.cc">
+      <Filter>test\cpp\interop</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\interop\http2_client.h">
+      <Filter>test\cpp\interop</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{8f01743f-58cf-2127-20d1-21303c8e0e8e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{219dd0bc-d605-d0fa-cca4-460276dd64cf}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{7ee50971-dbc6-3240-e6a2-a432dac43e90}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\testing">
+      <UniqueIdentifier>{66289b19-9541-151c-03a1-771101833b4e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{18fdd193-31a2-a622-980e-df055c23af50}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{f6da8892-ac51-d835-468a-b3b093df4baa}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\interop">
+      <UniqueIdentifier>{e32cff29-3247-cece-56cf-8fd16a1a79fe}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/interop_server_helper/interop_server_helper.vcxproj b/vsprojects/vcxproj/interop_server_helper/interop_server_helper.vcxproj
index 4c99988..377cadc 100644
--- a/vsprojects/vcxproj/interop_server_helper/interop_server_helper.vcxproj
+++ b/vsprojects/vcxproj/interop_server_helper/interop_server_helper.vcxproj
@@ -154,6 +154,9 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
+      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj
index a2b2a1d..d2699a5 100644
--- a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj
+++ b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj
@@ -191,6 +191,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
diff --git a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters
index 94b6c25..dc0d89e 100644
--- a/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters
+++ b/vsprojects/vcxproj/test/codegen_test_full/codegen_test_full.vcxproj.filters
@@ -114,6 +114,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj
index 1a3c157..742c9a6 100644
--- a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj
+++ b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj
@@ -191,6 +191,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
diff --git a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters
index 1f4b60c..8816516 100644
--- a/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters
+++ b/vsprojects/vcxproj/test/codegen_test_minimal/codegen_test_minimal.vcxproj.filters
@@ -117,6 +117,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
index 1e3cc3c..65719c3 100644
--- a/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
+++ b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
@@ -192,6 +192,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
diff --git a/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters
index 1c308c5..7f3745c 100644
--- a/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters
@@ -108,6 +108,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\exec_ctx_fwd.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/memory_profile_client/memory_profile_client.vcxproj b/vsprojects/vcxproj/test/memory_profile_client/memory_profile_client.vcxproj
new file mode 100644
index 0000000..b955bca
--- /dev/null
+++ b/vsprojects/vcxproj/test/memory_profile_client/memory_profile_client.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{98C01DBE-EFFE-6988-0762-829DC88F0EB4}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>memory_profile_client</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>memory_profile_client</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\memory_usage\client.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/memory_profile_client/memory_profile_client.vcxproj.filters b/vsprojects/vcxproj/test/memory_profile_client/memory_profile_client.vcxproj.filters
new file mode 100644
index 0000000..b250b53
--- /dev/null
+++ b/vsprojects/vcxproj/test/memory_profile_client/memory_profile_client.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\memory_usage\client.c">
+      <Filter>test\core\memory_usage</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{4445c589-fe29-9a74-3b53-c83c7bac669e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{8f263e3f-4f47-64ed-e45f-8f4385a6056d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\memory_usage">
+      <UniqueIdentifier>{2de23f1d-3faf-3318-2e31-b7cfa4a89220}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/memory_profile_server/memory_profile_server.vcxproj b/vsprojects/vcxproj/test/memory_profile_server/memory_profile_server.vcxproj
new file mode 100644
index 0000000..0b3c879
--- /dev/null
+++ b/vsprojects/vcxproj/test/memory_profile_server/memory_profile_server.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{7430B8AF-2A0E-EDF4-FD53-C8004DEE39EC}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>memory_profile_server</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>memory_profile_server</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\memory_usage\server.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/memory_profile_server/memory_profile_server.vcxproj.filters b/vsprojects/vcxproj/test/memory_profile_server/memory_profile_server.vcxproj.filters
new file mode 100644
index 0000000..c95888e
--- /dev/null
+++ b/vsprojects/vcxproj/test/memory_profile_server/memory_profile_server.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\memory_usage\server.c">
+      <Filter>test\core\memory_usage</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{0193b199-ddad-5387-8a4f-ab1e6c36b835}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{31db3ee2-d7ca-bedb-eacc-1bc7785dcae6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\memory_usage">
+      <UniqueIdentifier>{5b7c6ebd-9730-e59c-59bf-806a8b7ccda2}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+