Merge branch 'v1.0.x' of https://github.com/grpc/grpc
diff --git a/.gitignore b/.gitignore
index f379891..ed015b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 # C/C++ build outputs
+.build/
 bins
 gens
 libs
@@ -96,3 +97,9 @@
 
 # Artifacts directory
 artifacts/
+
+# Git generated files for conflicting
+*.orig
+
+# IDE specific folder for JetBrains IDEs
+.idea/
diff --git a/.gitmodules b/.gitmodules
index d41b8d5..92d5ac3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -17,3 +17,6 @@
 [submodule "third_party/nanopb"]
 	path = third_party/nanopb
 	url = https://github.com/nanopb/nanopb.git
+[submodule "third_party/thrift"]
+	path = third_party/thrift
+	url = https://github.com/apache/thrift.git
diff --git a/BUILD b/BUILD
index 6e1289d..b36ce25 100644
--- a/BUILD
+++ b/BUILD
@@ -165,6 +165,7 @@
     "src/core/lib/channel/compress_filter.h",
     "src/core/lib/channel/connected_channel.h",
     "src/core/lib/channel/context.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/compression/algorithm_metadata.h",
@@ -235,6 +236,7 @@
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.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",
@@ -256,7 +258,6 @@
     "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/timeout_encoding.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",
@@ -299,16 +300,19 @@
     "src/core/ext/client_config/subchannel_call_holder.h",
     "src/core/ext/client_config/subchannel_index.h",
     "src/core/ext/client_config/uri_parser.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/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/lib/surface/init.c",
     "src/core/lib/channel/channel_args.c",
@@ -316,6 +320,7 @@
     "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/handshaker.c",
     "src/core/lib/channel/http_client_filter.c",
     "src/core/lib/channel/http_server_filter.c",
     "src/core/lib/compression/compression.c",
@@ -396,6 +401,7 @@
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.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",
@@ -418,7 +424,6 @@
     "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/timeout_encoding.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",
@@ -474,6 +479,7 @@
     "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",
@@ -482,6 +488,7 @@
     "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/grpc_context.c",
@@ -491,6 +498,7 @@
     "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/tracing.c",
     "src/core/plugin_registry/grpc_plugin_registry.c",
   ],
@@ -552,6 +560,7 @@
     "src/core/lib/channel/compress_filter.h",
     "src/core/lib/channel/connected_channel.h",
     "src/core/lib/channel/context.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/compression/algorithm_metadata.h",
@@ -622,6 +631,7 @@
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.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",
@@ -644,7 +654,6 @@
     "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/timeout_encoding.h",
     "src/core/ext/transport/chttp2/transport/varint.h",
     "src/core/ext/transport/chttp2/alpn/alpn.h",
     "src/core/ext/client_config/client_channel.h",
@@ -693,6 +702,7 @@
     "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/handshaker.c",
     "src/core/lib/channel/http_client_filter.c",
     "src/core/lib/channel/http_server_filter.c",
     "src/core/lib/compression/compression.c",
@@ -773,6 +783,7 @@
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.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",
@@ -798,7 +809,6 @@
     "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/timeout_encoding.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",
@@ -904,6 +914,7 @@
     "src/core/lib/channel/compress_filter.h",
     "src/core/lib/channel/connected_channel.h",
     "src/core/lib/channel/context.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/compression/algorithm_metadata.h",
@@ -974,6 +985,7 @@
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.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",
@@ -995,7 +1007,6 @@
     "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/timeout_encoding.h",
     "src/core/ext/transport/chttp2/transport/varint.h",
     "src/core/ext/transport/chttp2/alpn/alpn.h",
     "src/core/ext/client_config/client_channel.h",
@@ -1016,14 +1027,17 @@
     "src/core/ext/client_config/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/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/lib/surface/init.c",
     "src/core/lib/surface/init_unsecure.c",
@@ -1032,6 +1046,7 @@
     "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/handshaker.c",
     "src/core/lib/channel/http_client_filter.c",
     "src/core/lib/channel/http_server_filter.c",
     "src/core/lib/compression/compression.c",
@@ -1112,6 +1127,7 @@
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.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",
@@ -1135,7 +1151,6 @@
     "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/timeout_encoding.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",
@@ -1164,10 +1179,12 @@
     "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/grpc_context.c",
@@ -1177,6 +1194,7 @@
     "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/tracing.c",
     "src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
   ],
@@ -1234,6 +1252,7 @@
     "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/core/lib/channel/channel_args.h",
@@ -1242,6 +1261,7 @@
     "src/core/lib/channel/compress_filter.h",
     "src/core/lib/channel/connected_channel.h",
     "src/core/lib/channel/context.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/compression/algorithm_metadata.h",
@@ -1312,6 +1332,7 @@
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.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/cpp/client/secure_credentials.cc",
@@ -1329,6 +1350,7 @@
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.cc",
     "src/cpp/common/channel_arguments.cc",
+    "src/cpp/common/channel_filter.cc",
     "src/cpp/common/completion_queue.cc",
     "src/cpp/common/core_codegen.cc",
     "src/cpp/common/rpc_method.cc",
@@ -1351,6 +1373,7 @@
     "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/handshaker.c",
     "src/core/lib/channel/http_client_filter.c",
     "src/core/lib/channel/http_server_filter.c",
     "src/core/lib/compression/compression.c",
@@ -1431,6 +1454,7 @@
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc",
@@ -1638,6 +1662,7 @@
   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/core/lib/channel/channel_args.h",
@@ -1646,6 +1671,7 @@
     "src/core/lib/channel/compress_filter.h",
     "src/core/lib/channel/connected_channel.h",
     "src/core/lib/channel/context.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/compression/algorithm_metadata.h",
@@ -1716,6 +1742,7 @@
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.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/cpp/common/insecure_create_auth_context.cc",
@@ -1728,6 +1755,7 @@
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.cc",
     "src/cpp/common/channel_arguments.cc",
+    "src/cpp/common/channel_filter.cc",
     "src/cpp/common/completion_queue.cc",
     "src/cpp/common/core_codegen.cc",
     "src/cpp/common/rpc_method.cc",
@@ -1750,6 +1778,7 @@
     "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/handshaker.c",
     "src/core/lib/channel/http_client_filter.c",
     "src/core/lib/channel/http_server_filter.c",
     "src/core/lib/compression/compression.c",
@@ -1830,6 +1859,7 @@
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc",
@@ -2136,6 +2166,7 @@
     "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/handshaker.c",
     "src/core/lib/channel/http_client_filter.c",
     "src/core/lib/channel/http_server_filter.c",
     "src/core/lib/compression/compression.c",
@@ -2216,6 +2247,7 @@
     "src/core/lib/transport/metadata.c",
     "src/core/lib/transport/metadata_batch.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",
@@ -2238,7 +2270,6 @@
     "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/timeout_encoding.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",
@@ -2294,6 +2325,7 @@
     "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",
@@ -2302,6 +2334,7 @@
     "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/grpc_context.c",
@@ -2311,6 +2344,7 @@
     "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/tracing.c",
     "src/core/plugin_registry/grpc_plugin_registry.c",
   ],
@@ -2351,6 +2385,7 @@
     "src/core/lib/channel/compress_filter.h",
     "src/core/lib/channel/connected_channel.h",
     "src/core/lib/channel/context.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/compression/algorithm_metadata.h",
@@ -2421,6 +2456,7 @@
     "src/core/lib/transport/metadata.h",
     "src/core/lib/transport/metadata_batch.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",
@@ -2442,7 +2478,6 @@
     "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/timeout_encoding.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",
@@ -2485,16 +2520,19 @@
     "src/core/ext/client_config/subchannel_call_holder.h",
     "src/core/ext/client_config/subchannel_index.h",
     "src/core/ext/client_config/uri_parser.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/grpc_filter.h",
     "src/core/ext/census/mlog.h",
+    "src/core/ext/census/resource.h",
     "src/core/ext/census/rpc_metric_id.h",
   ],
   includes = [
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 44e9072..fbcc6bb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,35 +42,132 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.0.1-pre1")
+set(PACKAGE_VERSION   "1.1.0-dev")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
 project(${PACKAGE_NAME} C CXX)
 
-if(NOT BORINGSSL_ROOT_DIR)
-  set(BORINGSSL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/boringssl)
-endif()
-if(NOT PROTOBUF_ROOT_DIR)
-  set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf)
-endif()
-if(NOT ZLIB_ROOT_DIR)
-  set(ZLIB_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/zlib)
+if (NOT MSVC)
+  set(gRPC_INSTALL ON CACHE BOOL "Generate installation target")
+else()
+  set(gRPC_INSTALL OFF CACHE BOOL "Generate installation target")
 endif()
 
-# Building the protobuf tests require gmock what is not part of a standard protobuf checkout.
-# Disable them unless they are explicitly requested from the cmake command line (when we assume
-# gmock is downloaded to the right location inside protobuf).
-if(NOT protobuf_BUILD_TESTS)
-  set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests")
+set(gRPC_ZLIB_PROVIDER "module" CACHE STRING "Provider of zlib library")
+set_property(CACHE gRPC_ZLIB_PROVIDER PROPERTY STRINGS "module" "package")
+
+set(gRPC_SSL_PROVIDER "module" CACHE STRING "Provider of ssl library")
+set_property(CACHE gRPC_SSL_PROVIDER PROPERTY STRINGS "module" "package")
+
+set(gRPC_PROTOBUF_PROVIDER "module" CACHE STRING "Provider of protobuf library")
+set_property(CACHE gRPC_PROTOBUF_PROVIDER PROPERTY STRINGS "module" "package")
+
+set(gRPC_USE_PROTO_LITE OFF CACHE BOOL "Use the protobuf-lite library")
+
+if (MSVC)
+  add_definitions( -D_WIN32_WINNT=0x600 )
 endif()
 
-add_subdirectory(${BORINGSSL_ROOT_DIR} third_party/boringssl)
-add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake third_party/protobuf)
-add_subdirectory(${ZLIB_ROOT_DIR} third_party/zlib)
+if (gRPC_USE_PROTO_LITE)
+  set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf-lite")
+  add_definitions("-DGRPC_USE_PROTO_LITE")
+else()
+  set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf")
+endif()
 
-set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -std=c11")
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+if("${gRPC_ZLIB_PROVIDER}" STREQUAL "module")
+  if(NOT ZLIB_ROOT_DIR)
+    set(ZLIB_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/zlib)
+  endif()
+  set(ZLIB_INCLUDE_DIR "${ZLIB_ROOT_DIR}")
+  if(EXISTS "${ZLIB_ROOT_DIR}/CMakeLists.txt")
+      add_subdirectory(${ZLIB_ROOT_DIR} third_party/zlib)
+      if(TARGET zlibstatic)
+          set(_gRPC_ZLIB_LIBRARIES zlibstatic)
+      endif()
+  else()
+      message(WARNING "gRPC_ZLIB_PROVIDER is \"module\" but ZLIB_ROOT_DIR is wrong")
+  endif()
+elseif("${gRPC_ZLIB_PROVIDER}" STREQUAL "package")
+  find_package(ZLIB)
+  if(TARGET ZLIB::ZLIB)
+    set(_gRPC_ZLIB_LIBRARIES ZLIB::ZLIB)
+  endif()
+  set(_gRPC_FIND_ZLIB "if(NOT ZLIB_FOUND)\n  find_package(ZLIB)\nendif()")
+endif()
+
+if("${gRPC_PROTOBUF_PROVIDER}" STREQUAL "module")
+  # Building the protobuf tests require gmock what is not part of a standard protobuf checkout.
+  # Disable them unless they are explicitly requested from the cmake command line (when we assume
+  # gmock is downloaded to the right location inside protobuf).
+  if(NOT protobuf_BUILD_TESTS)
+    set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests")
+  endif()
+  if(NOT PROTOBUF_ROOT_DIR)
+    set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf)
+  endif()
+  if(EXISTS "${PROTOBUF_ROOT_DIR}/cmake/CMakeLists.txt")
+    set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Link static runtime libraries")
+    add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake third_party/protobuf)
+    if(TARGET ${_gRPC_PROTOBUF_LIBRARY_NAME})
+      set(_gRPC_PROTOBUF_LIBRARIES ${_gRPC_PROTOBUF_LIBRARY_NAME})
+    endif()
+    if(TARGET libprotoc)
+      set(_gRPC_PROTOBUF_PROTOC_LIBRARIES libprotoc)
+    endif()
+  else()
+      message(WARNING "gRPC_PROTOBUF_PROVIDER is \"module\" but PROTOBUF_ROOT_DIR is wrong")
+  endif()
+elseif("${gRPC_PROTOBUF_PROVIDER}" STREQUAL "package")
+  find_package(protobuf CONFIG)
+  if(protobuf_FOUND)
+    if(TARGET protobuf::${_gRPC_PROTOBUF_LIBRARY_NAME})
+      set(_gRPC_PROTOBUF_LIBRARIES protobuf::${_gRPC_PROTOBUF_LIBRARY_NAME})
+    endif()
+    if(TARGET protobuf::libprotoc)
+      set(_gRPC_PROTOBUF_PROTOC_LIBRARIES protobuf::libprotoc)
+    endif()
+    set(_gRPC_FIND_PROTOBUF "if(NOT protobuf_FOUND)\n  find_package(protobuf CONFIG)\nendif()")
+  else()
+    find_package(Protobuf MODULE)
+    set(_gRPC_FIND_PROTOBUF "if(NOT Protobuf_FOUND)\n  find_package(Protobuf)\nendif()")
+  endif()
+endif()
+
+if("${gRPC_SSL_PROVIDER}" STREQUAL "module")
+  if(NOT BORINGSSL_ROOT_DIR)
+    set(BORINGSSL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/boringssl)
+  endif()
+  if(EXISTS "${BORINGSSL_ROOT_DIR}/CMakeLists.txt")
+    add_subdirectory(${BORINGSSL_ROOT_DIR} third_party/boringssl)
+    if(TARGET ssl)
+      set(_gRPC_SSL_LIBRARIES ssl)
+    endif()
+  else()
+      message(WARNING "gRPC_SSL_PROVIDER is \"module\" but BORINGSSL_ROOT_DIR is wrong")
+  endif()
+elseif("${gRPC_SSL_PROVIDER}" STREQUAL "package")
+  find_package(OpenSSL)
+  if(TARGET OpenSSL::SSL)
+    set(_gRPC_SSL_LIBRARIES OpenSSL::SSL)
+  endif()
+  set(_gRPC_FIND_SSL "if(NOT OpenSSL_FOUND)\n  find_package(OpenSSL)\nendif()")
+endif()
+
+if(NOT MSVC)
+  set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -std=c11")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+endif()
+
+if(WIN32 AND MSVC)
+  set(_gRPC_BASELIB_LIBRARIES wsock32 ws2_32)
+endif()
+
+include(GNUInstallDirs)
+if(NOT DEFINED CMAKE_INSTALL_CMAKEDIR)
+  set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/gRPC")
+endif()
 
   
 add_library(gpr
@@ -126,11 +223,71 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 
+foreach(_hdr
+  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/slice.h
+  include/grpc/support/slice_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/time.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 gpr EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc
   src/core/lib/surface/init.c
@@ -139,6 +296,7 @@
   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/handshaker.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/compression/compression.c
@@ -219,6 +377,7 @@
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.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
@@ -241,7 +400,6 @@
   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/timeout_encoding.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
@@ -297,6 +455,7 @@
   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
@@ -308,6 +467,7 @@
   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/grpc_context.c
@@ -317,6 +477,7 @@
   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/tracing.c
   src/core/plugin_registry/grpc_plugin_registry.c
 )
@@ -326,16 +487,65 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 target_link_libraries(grpc
-  ssl
-  zlibstatic
+  ${_gRPC_BASELIB_LIBRARIES}
+  ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_ZLIB_LIBRARIES}
   gpr
 )
 
+foreach(_hdr
+  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/status.h
+  include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/time.h
+  include/grpc/grpc_security.h
+  include/grpc/census.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 EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc_cronet
   src/core/lib/surface/init.c
@@ -344,6 +554,7 @@
   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/handshaker.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/compression/compression.c
@@ -424,6 +635,7 @@
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.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
@@ -449,7 +661,6 @@
   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/timeout_encoding.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
@@ -508,15 +719,64 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 target_link_libraries(grpc_cronet
-  ssl
+  ${_gRPC_BASELIB_LIBRARIES}
+  ${_gRPC_SSL_LIBRARIES}
   gpr
 )
 
+foreach(_hdr
+  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/status.h
+  include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/time.h
+  include/grpc/grpc_cronet.h
+  include/grpc/grpc_security.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_cronet EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc_unsecure
   src/core/lib/surface/init.c
@@ -526,6 +786,7 @@
   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/handshaker.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/compression/compression.c
@@ -606,6 +867,7 @@
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.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
@@ -629,7 +891,6 @@
   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/timeout_encoding.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
@@ -658,6 +919,7 @@
   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
   third_party/nanopb/pb_common.c
@@ -665,6 +927,7 @@
   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/census/base_resources.c
   src/core/ext/census/context.c
   src/core/ext/census/gen/census.pb.c
   src/core/ext/census/grpc_context.c
@@ -674,6 +937,7 @@
   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/tracing.c
   src/core/plugin_registry/grpc_unsecure_plugin_registry.c
 )
@@ -683,14 +947,62 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 target_link_libraries(grpc_unsecure
+  ${_gRPC_BASELIB_LIBRARIES}
   gpr
 )
 
+foreach(_hdr
+  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/status.h
+  include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/time.h
+  include/grpc/census.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_unsecure EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc++
   src/cpp/client/secure_credentials.cc
@@ -708,6 +1020,7 @@
   src/cpp/client/generic_stub.cc
   src/cpp/client/insecure_credentials.cc
   src/cpp/common/channel_arguments.cc
+  src/cpp/common/channel_filter.cc
   src/cpp/common/completion_queue.cc
   src/cpp/common/core_codegen.cc
   src/cpp/common/rpc_method.cc
@@ -730,6 +1043,7 @@
   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/handshaker.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/compression/compression.c
@@ -810,6 +1124,7 @@
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc
@@ -820,17 +1135,141 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 target_link_libraries(grpc++
-  ssl
-  libprotobuf
+  ${_gRPC_BASELIB_LIBRARIES}
+  ${_gRPC_SSL_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   grpc
   gpr
 )
 
+foreach(_hdr
+  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.h
+  include/grpc++/impl/sync_cxx11.h
+  include/grpc++/impl/sync_no_cxx11.h
+  include/grpc++/impl/thd.h
+  include/grpc++/impl/thd_cxx11.h
+  include/grpc++/impl/thd_no_cxx11.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/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/status.h
+  include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/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/string_ref.h
+  include/grpc++/impl/codegen/stub_options.h
+  include/grpc++/impl/codegen/sync.h
+  include/grpc++/impl/codegen/sync_cxx11.h
+  include/grpc++/impl/codegen/sync_no_cxx11.h
+  include/grpc++/impl/codegen/sync_stream.h
+  include/grpc++/impl/codegen/time.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++ EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc++_reflection
   src/cpp/ext/proto_server_reflection.cc
@@ -844,7 +1283,7 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
@@ -852,6 +1291,80 @@
   grpc++
 )
 
+foreach(_hdr
+  include/grpc++/ext/proto_server_reflection_plugin.h
+  include/grpc++/ext/reflection.grpc.pb.h
+  include/grpc++/ext/reflection.pb.h
+  include/grpc++/impl/codegen/proto_utils.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/string_ref.h
+  include/grpc++/impl/codegen/stub_options.h
+  include/grpc++/impl/codegen/sync.h
+  include/grpc++/impl/codegen/sync_cxx11.h
+  include/grpc++/impl/codegen/sync_no_cxx11.h
+  include/grpc++/impl/codegen/sync_stream.h
+  include/grpc++/impl/codegen/time.h
+  include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/time.h
+  include/grpc++/impl/codegen/config_protobuf.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/common/insecure_create_auth_context.cc
@@ -864,6 +1377,7 @@
   src/cpp/client/generic_stub.cc
   src/cpp/client/insecure_credentials.cc
   src/cpp/common/channel_arguments.cc
+  src/cpp/common/channel_filter.cc
   src/cpp/common/completion_queue.cc
   src/cpp/common/core_codegen.cc
   src/cpp/common/rpc_method.cc
@@ -886,6 +1400,7 @@
   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/handshaker.c
   src/core/lib/channel/http_client_filter.c
   src/core/lib/channel/http_server_filter.c
   src/core/lib/compression/compression.c
@@ -966,6 +1481,7 @@
   src/core/lib/transport/metadata.c
   src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc
@@ -976,16 +1492,140 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 target_link_libraries(grpc++_unsecure
-  libprotobuf
+  ${_gRPC_BASELIB_LIBRARIES}
+  ${_gRPC_PROTOBUF_LIBRARIES}
   gpr
   grpc_unsecure
 )
 
+foreach(_hdr
+  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.h
+  include/grpc++/impl/sync_cxx11.h
+  include/grpc++/impl/sync_no_cxx11.h
+  include/grpc++/impl/thd.h
+  include/grpc++/impl/thd_cxx11.h
+  include/grpc++/impl/thd_no_cxx11.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/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/status.h
+  include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.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/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/string_ref.h
+  include/grpc++/impl/codegen/stub_options.h
+  include/grpc++/impl/codegen/sync.h
+  include/grpc++/impl/codegen/sync_cxx11.h
+  include/grpc++/impl/codegen/sync_no_cxx11.h
+  include/grpc++/impl/codegen/sync_stream.h
+  include/grpc++/impl/codegen/time.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++_unsecure EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc_plugin_support
   src/compiler/cpp_generator.cc
@@ -1001,14 +1641,33 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
 target_link_libraries(grpc_plugin_support
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
 )
 
+foreach(_hdr
+  include/grpc++/impl/codegen/config_protobuf.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_plugin_support EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
   
 add_library(grpc_csharp_ext
   src/csharp/ext/grpc_csharp_ext.c
@@ -1019,7 +1678,7 @@
   PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
   PRIVATE ${BORINGSSL_ROOT_DIR}/include
   PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${ZLIB_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
 )
 
@@ -1029,6 +1688,16 @@
 )
 
 
+  
+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
   tools/codegen/core/gen_hpack_tables.c
@@ -1049,6 +1718,15 @@
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS gen_hpack_tables EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(gen_legal_metadata_characters
   tools/codegen/core/gen_legal_metadata_characters.c
 )
@@ -1064,6 +1742,15 @@
 
 
 
+if (gRPC_INSTALL)
+  install(TARGETS gen_legal_metadata_characters EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_create_jwt
   test/core/security/create_jwt.c
 )
@@ -1078,12 +1765,21 @@
 )
 
 target_link_libraries(grpc_create_jwt
-  ssl
+  ${_gRPC_SSL_LIBRARIES}
   grpc
   gpr
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_create_jwt EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_print_google_default_creds_token
   test/core/security/print_google_default_creds_token.c
 )
@@ -1103,6 +1799,15 @@
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_print_google_default_creds_token EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_verify_jwt
   test/core/security/verify_jwt.c
 )
@@ -1122,6 +1827,15 @@
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_verify_jwt EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_cpp_plugin
   src/compiler/cpp_plugin.cc
 )
@@ -1136,11 +1850,20 @@
 )
 
 target_link_libraries(grpc_cpp_plugin
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_plugin_support
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_cpp_plugin EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_csharp_plugin
   src/compiler/csharp_plugin.cc
 )
@@ -1155,11 +1878,20 @@
 )
 
 target_link_libraries(grpc_csharp_plugin
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_plugin_support
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_csharp_plugin EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_node_plugin
   src/compiler/node_plugin.cc
 )
@@ -1174,11 +1906,20 @@
 )
 
 target_link_libraries(grpc_node_plugin
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_plugin_support
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_node_plugin EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_objective_c_plugin
   src/compiler/objective_c_plugin.cc
 )
@@ -1193,11 +1934,20 @@
 )
 
 target_link_libraries(grpc_objective_c_plugin
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_plugin_support
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_objective_c_plugin EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_python_plugin
   src/compiler/python_plugin.cc
 )
@@ -1212,11 +1962,20 @@
 )
 
 target_link_libraries(grpc_python_plugin
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_plugin_support
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_python_plugin EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
+
+
 add_executable(grpc_ruby_plugin
   src/compiler/ruby_plugin.cc
 )
@@ -1231,11 +1990,37 @@
 )
 
 target_link_libraries(grpc_ruby_plugin
-  libprotoc
+  ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_plugin_support
 )
 
 
+if (gRPC_INSTALL)
+  install(TARGETS grpc_ruby_plugin EXPORT gRPCTargets
+    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+  )
+endif()
 
 
 
+
+
+
+
+
+if (gRPC_INSTALL)
+  install(EXPORT gRPCTargets
+    DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
+    NAMESPACE gRPC::
+  )
+endif()
+
+foreach(_config gRPCConfig gRPCConfigVersion)
+  configure_file(tools/cmake/${_config}.cmake.in
+    ${_config}.cmake @ONLY)
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_config}.cmake
+    DESTINATION ${CMAKE_INSTALL_CMAKEDIR}
+  )
+endforeach()
diff --git a/Makefile b/Makefile
index da53211..c7622c0 100644
--- a/Makefile
+++ b/Makefile
@@ -405,6 +405,29 @@
 LDFLAGS += -pthread
 endif
 
+#
+# The steps for cross-compiling are as follows:
+# First, clone and make install of grpc using the native compilers for the host.
+# Also, install protoc (e.g., from a package like apt-get)
+# Then clone a fresh grpc for the actual cross-compiled build
+# Set the environment variable GRPC_CROSS_COMPILE to true
+# Set CC, CXX, LD, LDXX, AR, and STRIP to the cross-compiling binaries
+# Also set PROTOBUF_CONFIG_OPTS to indicate cross-compilation to protobuf (e.g.,
+#  PROTOBUF_CONFIG_OPTS="--host=arm-linux --with-protoc=/usr/local/bin/protoc" )
+# Set HAS_PKG_CONFIG=false
+# To build tests, go to third_party/gflags and follow its ccmake instructions
+# Make sure that you enable building shared libraries and set your prefix to
+# something useful like /usr/local/cross
+# You will also need to set GRPC_CROSS_LDOPTS and GRPC_CROSS_AROPTS to hold
+# additional required arguments for LD and AR (examples below)
+# Then you can do a make from the cross-compiling fresh clone!
+#
+ifeq ($(GRPC_CROSS_COMPILE),true)
+LDFLAGS += $(GRPC_CROSS_LDOPTS) # e.g. -L/usr/local/lib -L/usr/local/cross/lib
+AROPTS = $(GRPC_CROSS_AROPTS) # e.g., rc --target=elf32-little
+USE_BUILT_PROTOC = false
+endif
+
 GTEST_LIB = -Ithird_party/googletest/include -Ithird_party/googletest third_party/googletest/src/gtest-all.cc
 GTEST_LIB += -lgflags
 ifeq ($(V),1)
@@ -415,7 +438,7 @@
 Q = @
 endif
 
-VERSION = 1.0.1-pre1
+VERSION = 1.1.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -709,6 +732,9 @@
 
 CPPFLAGS := -Ithird_party/googletest/include $(CPPFLAGS)
 
+PROTOC_PLUGINS_ALL = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG)
+
 ifeq ($(HAS_SYSTEM_PROTOBUF),true)
 ifeq ($(HAS_PKG_CONFIG),true)
 PROTOBUF_PKG_CONFIG = true
@@ -723,12 +749,19 @@
 else
 PC_LIBS_GRPCXX = -lprotobuf
 endif
+PROTOC_PLUGINS = $(PROTOC_PLUGINS_ALL)
 else
 ifeq ($(HAS_EMBEDDED_PROTOBUF),true)
 PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a
 CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS)
 LDFLAGS := -L$(LIBDIR)/$(CONFIG)/protobuf $(LDFLAGS)
+ifneq ($(USE_BUILT_PROTOC),false)
 PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc
+PROTOC_PLUGINS = $(PROTOC_PLUGINS_ALL)
+else
+PROTOC_PLUGINS =
+PROTOC_PLUGINS_DIR = $(prefix)/bin
+endif
 else
 NO_PROTOBUF = true
 endif
@@ -769,7 +802,6 @@
 
 .SECONDARY = %.pb.h %.pb.cc
 
-PROTOC_PLUGINS = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
 ifeq ($(DEP_MISSING),)
 all: static shared plugins
 dep_error:
@@ -876,6 +908,7 @@
 bin_decoder_test: $(BINDIR)/$(CONFIG)/bin_decoder_test
 bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test
 census_context_test: $(BINDIR)/$(CONFIG)/census_context_test
+census_resource_test: $(BINDIR)/$(CONFIG)/census_resource_test
 channel_create_test: $(BINDIR)/$(CONFIG)/channel_create_test
 chttp2_hpack_encoder_test: $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test
 chttp2_status_conversion_test: $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test
@@ -999,6 +1032,7 @@
 cxx_string_ref_test: $(BINDIR)/$(CONFIG)/cxx_string_ref_test
 cxx_time_test: $(BINDIR)/$(CONFIG)/cxx_time_test
 end2end_test: $(BINDIR)/$(CONFIG)/end2end_test
+filter_end2end_test: $(BINDIR)/$(CONFIG)/filter_end2end_test
 generic_end2end_test: $(BINDIR)/$(CONFIG)/generic_end2end_test
 golden_file_test: $(BINDIR)/$(CONFIG)/golden_file_test
 grpc_cli: $(BINDIR)/$(CONFIG)/grpc_cli
@@ -1008,7 +1042,9 @@
 grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
 grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin
 grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+grpc_tool_test: $(BINDIR)/$(CONFIG)/grpc_tool_test
 grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test
+grpclb_test: $(BINDIR)/$(CONFIG)/grpclb_test
 hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
 interop_client: $(BINDIR)/$(CONFIG)/interop_client
 interop_server: $(BINDIR)/$(CONFIG)/interop_server
@@ -1093,7 +1129,7 @@
 h2_full_test: $(BINDIR)/$(CONFIG)/h2_full_test
 h2_full+pipe_test: $(BINDIR)/$(CONFIG)/h2_full+pipe_test
 h2_full+trace_test: $(BINDIR)/$(CONFIG)/h2_full+trace_test
-h2_loadreporting_test: $(BINDIR)/$(CONFIG)/h2_loadreporting_test
+h2_load_reporting_test: $(BINDIR)/$(CONFIG)/h2_load_reporting_test
 h2_oauth2_test: $(BINDIR)/$(CONFIG)/h2_oauth2_test
 h2_proxy_test: $(BINDIR)/$(CONFIG)/h2_proxy_test
 h2_sockpair_test: $(BINDIR)/$(CONFIG)/h2_sockpair_test
@@ -1109,7 +1145,7 @@
 h2_full_nosec_test: $(BINDIR)/$(CONFIG)/h2_full_nosec_test
 h2_full+pipe_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test
 h2_full+trace_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+trace_nosec_test
-h2_loadreporting_nosec_test: $(BINDIR)/$(CONFIG)/h2_loadreporting_nosec_test
+h2_load_reporting_nosec_test: $(BINDIR)/$(CONFIG)/h2_load_reporting_nosec_test
 h2_proxy_nosec_test: $(BINDIR)/$(CONFIG)/h2_proxy_nosec_test
 h2_sockpair_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair_nosec_test
 h2_sockpair+trace_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test
@@ -1140,7 +1176,7 @@
 
 $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure
 	$(E) "[MAKE]    Building protobuf"
-	$(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g $(PROTOBUF_LDFLAGS_EXTRA)" CPPFLAGS="$(PIC_CPPFLAGS) $(CPPFLAGS_$(CONFIG)) -g $(PROTOBUF_CPPFLAGS_EXTRA)" ./configure --disable-shared --enable-static)
+	$(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g $(PROTOBUF_LDFLAGS_EXTRA)" CPPFLAGS="$(PIC_CPPFLAGS) $(CPPFLAGS_$(CONFIG)) -g $(PROTOBUF_CPPFLAGS_EXTRA)" ./configure --disable-shared --enable-static $(PROTOBUF_CONFIG_OPTS))
 	$(Q)$(MAKE) -C third_party/protobuf clean
 	$(Q)$(MAKE) -C third_party/protobuf
 	$(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf
@@ -1177,9 +1213,9 @@
 pc_cxx_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc
 
 ifeq ($(EMBED_OPENSSL),true)
-privatelibs_cxx:  $(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_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
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.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
 else
-privatelibs_cxx:  $(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_main.a $(LIBDIR)/$(CONFIG)/libqps.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.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
 endif
 
 
@@ -1194,6 +1230,7 @@
   $(BINDIR)/$(CONFIG)/bin_decoder_test \
   $(BINDIR)/$(CONFIG)/bin_encoder_test \
   $(BINDIR)/$(CONFIG)/census_context_test \
+  $(BINDIR)/$(CONFIG)/census_resource_test \
   $(BINDIR)/$(CONFIG)/channel_create_test \
   $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test \
   $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test \
@@ -1309,7 +1346,7 @@
   $(BINDIR)/$(CONFIG)/h2_full_test \
   $(BINDIR)/$(CONFIG)/h2_full+pipe_test \
   $(BINDIR)/$(CONFIG)/h2_full+trace_test \
-  $(BINDIR)/$(CONFIG)/h2_loadreporting_test \
+  $(BINDIR)/$(CONFIG)/h2_load_reporting_test \
   $(BINDIR)/$(CONFIG)/h2_oauth2_test \
   $(BINDIR)/$(CONFIG)/h2_proxy_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair_test \
@@ -1325,7 +1362,7 @@
   $(BINDIR)/$(CONFIG)/h2_full_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_full+trace_nosec_test \
-  $(BINDIR)/$(CONFIG)/h2_loadreporting_nosec_test \
+  $(BINDIR)/$(CONFIG)/h2_load_reporting_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_proxy_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test \
@@ -1360,10 +1397,13 @@
   $(BINDIR)/$(CONFIG)/cxx_string_ref_test \
   $(BINDIR)/$(CONFIG)/cxx_time_test \
   $(BINDIR)/$(CONFIG)/end2end_test \
+  $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
+  $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
+  $(BINDIR)/$(CONFIG)/grpclb_test \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
   $(BINDIR)/$(CONFIG)/interop_client \
   $(BINDIR)/$(CONFIG)/interop_server \
@@ -1444,10 +1484,13 @@
   $(BINDIR)/$(CONFIG)/cxx_string_ref_test \
   $(BINDIR)/$(CONFIG)/cxx_time_test \
   $(BINDIR)/$(CONFIG)/end2end_test \
+  $(BINDIR)/$(CONFIG)/filter_end2end_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/golden_file_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
+  $(BINDIR)/$(CONFIG)/grpc_tool_test \
   $(BINDIR)/$(CONFIG)/grpclb_api_test \
+  $(BINDIR)/$(CONFIG)/grpclb_test \
   $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
   $(BINDIR)/$(CONFIG)/interop_client \
   $(BINDIR)/$(CONFIG)/interop_server \
@@ -1497,6 +1540,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 )
 	$(E) "[RUN]     Testing census_context_test"
 	$(Q) $(BINDIR)/$(CONFIG)/census_context_test || ( echo test census_context_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_resource_test"
+	$(Q) $(BINDIR)/$(CONFIG)/census_resource_test || ( echo test census_resource_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_create_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_create_test || ( echo test channel_create_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_hpack_encoder_test"
@@ -1729,12 +1774,18 @@
 	$(Q) $(BINDIR)/$(CONFIG)/cxx_time_test || ( echo test cxx_time_test failed ; exit 1 )
 	$(E) "[RUN]     Testing end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/end2end_test || ( echo test end2end_test failed ; exit 1 )
+	$(E) "[RUN]     Testing filter_end2end_test"
+	$(Q) $(BINDIR)/$(CONFIG)/filter_end2end_test || ( echo test filter_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing generic_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing golden_file_test"
 	$(Q) $(BINDIR)/$(CONFIG)/golden_file_test || ( echo test golden_file_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpc_tool_test"
+	$(Q) $(BINDIR)/$(CONFIG)/grpc_tool_test || ( echo test grpc_tool_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpclb_api_test"
 	$(Q) $(BINDIR)/$(CONFIG)/grpclb_api_test || ( echo test grpclb_api_test failed ; exit 1 )
+	$(E) "[RUN]     Testing grpclb_test"
+	$(Q) $(BINDIR)/$(CONFIG)/grpclb_test || ( echo test grpclb_test failed ; exit 1 )
 	$(E) "[RUN]     Testing hybrid_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/hybrid_end2end_test || ( echo test hybrid_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing interop_test"
@@ -1879,7 +1930,22 @@
 $(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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
+endif
+
+ifeq ($(NO_PROTOC),true)
+$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: protoc_dep_error
+$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc: protoc_dep_error
+else
+$(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc: src/proto/grpc/reflection/v1alpha/reflection.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) 
+	$(E) "[PROTOC]  Generating protobuf CC file from $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
+
+$(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 $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1894,7 +1960,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1909,7 +1975,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1924,7 +1990,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1939,7 +2005,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1954,7 +2020,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1969,7 +2035,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1984,7 +2050,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -1999,7 +2065,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2014,7 +2080,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2029,7 +2095,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2044,7 +2110,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 ifeq ($(NO_PROTOC),true)
@@ -2059,7 +2125,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
 endif
 
 
@@ -2384,7 +2450,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBGPR_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBGPR_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgpr.a
 endif
@@ -2426,7 +2492,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgpr_test_util.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBGPR_TEST_UTIL_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBGPR_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgpr_test_util.a
 endif
@@ -2446,6 +2512,7 @@
     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/handshaker.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/compression/compression.c \
@@ -2526,6 +2593,7 @@
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.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 \
@@ -2548,7 +2616,6 @@
     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/timeout_encoding.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 \
@@ -2604,6 +2671,7 @@
     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 \
@@ -2615,6 +2683,7 @@
     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/grpc_context.c \
@@ -2624,6 +2693,7 @@
     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/tracing.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
 
@@ -2677,7 +2747,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc.a
 endif
@@ -2718,6 +2788,7 @@
     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/handshaker.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/compression/compression.c \
@@ -2798,6 +2869,7 @@
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.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 \
@@ -2823,7 +2895,6 @@
     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/timeout_encoding.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 \
@@ -2926,7 +2997,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBGRPC_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a $(LIBGRPC_CRONET_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_cronet.a
 endif
@@ -2978,87 +3049,12 @@
     test/core/util/port_server_client.c \
     test/core/util/port_windows.c \
     test/core/util/slice_splitter.c \
-
-PUBLIC_HEADERS_C += \
-
-LIBGRPC_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_SRC))))
-
-
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure libraries if you don't have OpenSSL.
-
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: openssl_dep_error
-
-
-else
-
-
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_TEST_UTIL_OBJS) 
-	$(E) "[AR]      Creating $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBGRPC_TEST_UTIL_OBJS) 
-ifeq ($(SYSTEM),Darwin)
-	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
-endif
-
-
-
-
-endif
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(LIBGRPC_TEST_UTIL_OBJS:.o=.dep)
-endif
-endif
-
-
-LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
-    test/core/end2end/cq_verifier.c \
-    test/core/end2end/fixtures/proxy.c \
-    test/core/iomgr/endpoint_tests.c \
-    test/core/util/grpc_profiler.c \
-    test/core/util/memory_counters.c \
-    test/core/util/mock_endpoint.c \
-    test/core/util/parse_hexstring.c \
-    test/core/util/passthru_endpoint.c \
-    test/core/util/port_posix.c \
-    test/core/util/port_server_client.c \
-    test/core/util/port_windows.c \
-    test/core/util/slice_splitter.c \
-
-PUBLIC_HEADERS_C += \
-
-LIBGRPC_TEST_UTIL_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_UNSECURE_SRC))))
-
-
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a: $(ZLIB_DEP)  $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
-	$(E) "[AR]      Creating $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
-ifeq ($(SYSTEM),Darwin)
-	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
-endif
-
-
-
-
-ifneq ($(NO_DEPS),true)
--include $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS:.o=.dep)
-endif
-
-
-LIBGRPC_UNSECURE_SRC = \
-    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/handshaker.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/compression/compression.c \
@@ -3139,6 +3135,200 @@
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.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 \
+
+PUBLIC_HEADERS_C += \
+    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/status.h \
+    include/grpc/impl/codegen/byte_buffer.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/alloc.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/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.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/time.h \
+
+LIBGRPC_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: openssl_dep_error
+
+
+else
+
+
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_TEST_UTIL_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBGRPC_TEST_UTIL_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+endif
+
+
+
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC_TEST_UTIL_OBJS:.o=.dep)
+endif
+endif
+
+
+LIBGRPC_TEST_UTIL_UNSECURE_SRC = \
+    test/core/end2end/cq_verifier.c \
+    test/core/end2end/fixtures/proxy.c \
+    test/core/iomgr/endpoint_tests.c \
+    test/core/util/grpc_profiler.c \
+    test/core/util/memory_counters.c \
+    test/core/util/mock_endpoint.c \
+    test/core/util/parse_hexstring.c \
+    test/core/util/passthru_endpoint.c \
+    test/core/util/port_posix.c \
+    test/core/util/port_server_client.c \
+    test/core/util/port_windows.c \
+    test/core/util/slice_splitter.c \
+
+PUBLIC_HEADERS_C += \
+
+LIBGRPC_TEST_UTIL_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_UNSECURE_SRC))))
+
+
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a: $(ZLIB_DEP)  $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
+endif
+
+
+
+
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS:.o=.dep)
+endif
+
+
+LIBGRPC_UNSECURE_SRC = \
+    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/handshaker.c \
+    src/core/lib/channel/http_client_filter.c \
+    src/core/lib/channel/http_server_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/endpoint.c \
+    src/core/lib/iomgr/endpoint_pair_posix.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_and_epoll_posix.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_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_windows.c \
+    src/core/lib/iomgr/pollset_windows.c \
+    src/core/lib/iomgr/resolve_address_posix.c \
+    src/core/lib/iomgr/resolve_address_windows.c \
+    src/core/lib/iomgr/sockaddr_utils.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_windows.c \
+    src/core/lib/iomgr/tcp_client_posix.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_windows.c \
+    src/core/lib/iomgr/tcp_windows.c \
+    src/core/lib/iomgr/time_averaged_stats.c \
+    src/core/lib/iomgr/timer.c \
+    src/core/lib/iomgr/timer_heap.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_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_posix.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/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/metadata.c \
+    src/core/lib/transport/metadata_batch.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 \
@@ -3162,7 +3352,6 @@
     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/timeout_encoding.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 \
@@ -3191,6 +3380,7 @@
     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 \
     third_party/nanopb/pb_common.c \
@@ -3198,6 +3388,7 @@
     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/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
     src/core/ext/census/grpc_context.c \
@@ -3207,6 +3398,7 @@
     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/tracing.c \
     src/core/plugin_registry/grpc_unsecure_plugin_registry.c \
 
@@ -3248,7 +3440,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 endif
@@ -3300,7 +3492,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libreconnect_server.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBRECONNECT_SERVER_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBRECONNECT_SERVER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libreconnect_server.a
 endif
@@ -3339,7 +3531,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBTEST_TCP_SERVER_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBTEST_TCP_SERVER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a
 endif
@@ -3372,6 +3564,7 @@
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
     src/cpp/common/channel_arguments.cc \
+    src/cpp/common/channel_filter.cc \
     src/cpp/common/completion_queue.cc \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/rpc_method.cc \
@@ -3394,6 +3587,7 @@
     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/handshaker.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/compression/compression.c \
@@ -3474,6 +3668,7 @@
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc \
@@ -3612,7 +3807,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++.a
 endif
@@ -3739,7 +3934,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBGRPC++_REFLECTION_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBGRPC++_REFLECTION_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a
 endif
@@ -3775,6 +3970,55 @@
 endif
 
 
+LIBGRPC++_REFLECTION_CODEGEN_SRC = \
+    $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.pb.cc $(GENDIR)/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc \
+
+PUBLIC_HEADERS_CXX += \
+
+LIBGRPC++_REFLECTION_CODEGEN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_REFLECTION_CODEGEN_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.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)/libgrpc++_reflection_codegen.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_REFLECTION_CODEGEN_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.a $(LIBGRPC++_REFLECTION_CODEGEN_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_reflection_codegen.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBGRPC++_REFLECTION_CODEGEN_OBJS:.o=.dep)
+endif
+endif
+
+
 LIBGRPC++_TEST_CONFIG_SRC = \
     test/cpp/util/test_config.cc \
 
@@ -3805,7 +4049,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBGRPC++_TEST_CONFIG_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBGRPC++_TEST_CONFIG_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 endif
@@ -3890,6 +4134,8 @@
     include/grpc/impl/codegen/time.h \
     include/grpc++/impl/codegen/proto_utils.h \
     include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/thrift_serializer.h \
+    include/grpc++/impl/codegen/thrift_utils.h \
 
 LIBGRPC++_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_TEST_UTIL_SRC))))
 
@@ -3916,7 +4162,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBGRPC++_TEST_UTIL_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBGRPC++_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a
 endif
@@ -3953,6 +4199,7 @@
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
     src/cpp/common/channel_arguments.cc \
+    src/cpp/common/channel_filter.cc \
     src/cpp/common/completion_queue.cc \
     src/cpp/common/core_codegen.cc \
     src/cpp/common/rpc_method.cc \
@@ -3975,6 +4222,7 @@
     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/handshaker.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/compression/compression.c \
@@ -4055,6 +4303,7 @@
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc \
@@ -4183,7 +4432,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 endif
@@ -4217,7 +4466,10 @@
 
 LIBGRPC_CLI_LIBS_SRC = \
     test/cpp/util/cli_call.cc \
+    test/cpp/util/cli_credentials.cc \
+    test/cpp/util/grpc_tool.cc \
     test/cpp/util/proto_file_parser.cc \
+    test/cpp/util/proto_reflection_descriptor_database.cc \
 
 PUBLIC_HEADERS_CXX += \
 
@@ -4246,7 +4498,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBGRPC_CLI_LIBS_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBGRPC_CLI_LIBS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a
 endif
@@ -4292,7 +4544,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(LIBGRPC_PLUGIN_SUPPORT_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(LIBGRPC_PLUGIN_SUPPORT_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 endif
@@ -4338,7 +4590,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBINTEROP_CLIENT_HELPER_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBINTEROP_CLIENT_HELPER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
 endif
@@ -4392,7 +4644,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBINTEROP_CLIENT_MAIN_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBINTEROP_CLIENT_MAIN_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
 endif
@@ -4443,7 +4695,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBINTEROP_SERVER_HELPER_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBINTEROP_SERVER_HELPER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
 endif
@@ -4462,7 +4714,7 @@
 endif
 
 
-LIBINTEROP_SERVER_MAIN_SRC = \
+LIBINTEROP_SERVER_LIB_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 \
@@ -4470,6 +4722,56 @@
 
 PUBLIC_HEADERS_CXX += \
 
+LIBINTEROP_SERVER_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_LIB_SRC))))
+
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL.
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_lib.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)/libinterop_server_lib.a: protobuf_dep_error
+
+
+else
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_LIB_OBJS) 
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBINTEROP_SERVER_LIB_OBJS) 
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBINTEROP_SERVER_LIB_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_server.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_SERVER_MAIN_SRC = \
+    test/cpp/interop/interop_server_bootstrap.cc \
+
+PUBLIC_HEADERS_CXX += \
+
 LIBINTEROP_SERVER_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_MAIN_SRC))))
 
 
@@ -4495,7 +4797,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBINTEROP_SERVER_MAIN_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBINTEROP_SERVER_MAIN_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
 endif
@@ -4512,7 +4814,6 @@
 -include $(LIBINTEROP_SERVER_MAIN_OBJS:.o=.dep)
 endif
 endif
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_server.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
 
 
 LIBQPS_SRC = \
@@ -4560,7 +4861,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libqps.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBQPS_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBQPS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libqps.a
 endif
@@ -4613,7 +4914,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a $(LIBGRPC_CSHARP_EXT_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a $(LIBGRPC_CSHARP_EXT_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a
 endif
@@ -4957,7 +5258,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl.a $(LIBBORINGSSL_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl.a $(LIBBORINGSSL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl.a
 endif
@@ -4995,7 +5296,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBBORINGSSL_TEST_UTIL_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBBORINGSSL_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a
 endif
@@ -5033,7 +5334,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBBORINGSSL_AES_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBBORINGSSL_AES_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a
 endif
@@ -5071,7 +5372,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a $(LIBBORINGSSL_ASN1_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_asn1_test_lib.a
 endif
@@ -5109,7 +5410,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a
 endif
@@ -5147,7 +5448,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBBORINGSSL_BIO_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBBORINGSSL_BIO_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a
 endif
@@ -5185,7 +5486,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBBORINGSSL_BN_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBBORINGSSL_BN_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a
 endif
@@ -5223,7 +5524,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a
 endif
@@ -5261,7 +5562,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a
 endif
@@ -5299,7 +5600,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a
 endif
@@ -5337,7 +5638,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a
 endif
@@ -5366,7 +5667,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a
 endif
@@ -5402,7 +5703,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a
 endif
@@ -5440,7 +5741,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBBORINGSSL_X25519_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBBORINGSSL_X25519_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a
 endif
@@ -5478,7 +5779,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBBORINGSSL_DH_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBBORINGSSL_DH_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a
 endif
@@ -5516,7 +5817,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a
 endif
@@ -5545,7 +5846,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a $(LIBBORINGSSL_DSA_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a $(LIBBORINGSSL_DSA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a
 endif
@@ -5581,7 +5882,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBBORINGSSL_EC_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBBORINGSSL_EC_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a
 endif
@@ -5610,7 +5911,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a $(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a $(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a
 endif
@@ -5646,7 +5947,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a
 endif
@@ -5684,7 +5985,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBBORINGSSL_ERR_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBBORINGSSL_ERR_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a
 endif
@@ -5722,7 +6023,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a
 endif
@@ -5760,7 +6061,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBBORINGSSL_EVP_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBBORINGSSL_EVP_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a
 endif
@@ -5798,7 +6099,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a
 endif
@@ -5827,7 +6128,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a
 endif
@@ -5863,7 +6164,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a
 endif
@@ -5892,7 +6193,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a
 endif
@@ -5919,7 +6220,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBBORINGSSL_GCM_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBBORINGSSL_GCM_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a
 endif
@@ -5955,7 +6256,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a
 endif
@@ -5993,7 +6294,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a
 endif
@@ -6031,7 +6332,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a
 endif
@@ -6060,7 +6361,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a
 endif
@@ -6096,7 +6397,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBBORINGSSL_RSA_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBBORINGSSL_RSA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a
 endif
@@ -6125,7 +6426,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a
 endif
@@ -6152,7 +6453,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a
 endif
@@ -6188,7 +6489,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBBORINGSSL_X509_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a $(LIBBORINGSSL_X509_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_x509_test_lib.a
 endif
@@ -6217,7 +6518,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a $(LIBBORINGSSL_TAB_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a $(LIBBORINGSSL_TAB_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a
 endif
@@ -6244,7 +6545,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a
 endif
@@ -6271,7 +6572,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a $(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a $(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a
 endif
@@ -6307,7 +6608,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBBORINGSSL_SSL_TEST_LIB_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBBORINGSSL_SSL_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
 endif
@@ -6349,7 +6650,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libz.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libz.a $(LIBZ_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libz.a $(LIBZ_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libz.a
 endif
@@ -6384,7 +6685,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_client_test.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBBAD_CLIENT_TEST_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBBAD_CLIENT_TEST_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libbad_client_test.a
 endif
@@ -6423,7 +6724,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBBAD_SSL_TEST_SERVER_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBBAD_SSL_TEST_SERVER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a
 endif
@@ -6456,6 +6757,7 @@
     test/core/end2end/tests/default_host.c \
     test/core/end2end/tests/disappearing_server.c \
     test/core/end2end/tests/empty_batch.c \
+    test/core/end2end/tests/filter_call_init_fails.c \
     test/core/end2end/tests/filter_causes_close.c \
     test/core/end2end/tests/graceful_server_shutdown.c \
     test/core/end2end/tests/high_initial_seqno.c \
@@ -6463,6 +6765,7 @@
     test/core/end2end/tests/idempotent_request.c \
     test/core/end2end/tests/invoke_large_request.c \
     test/core/end2end/tests/large_metadata.c \
+    test/core/end2end/tests/load_reporting_hook.c \
     test/core/end2end/tests/max_concurrent_streams.c \
     test/core/end2end/tests/max_message_length.c \
     test/core/end2end/tests/negative_deadline.c \
@@ -6502,7 +6805,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_tests.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBEND2END_TESTS_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBEND2END_TESTS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libend2end_tests.a
 endif
@@ -6534,6 +6837,7 @@
     test/core/end2end/tests/default_host.c \
     test/core/end2end/tests/disappearing_server.c \
     test/core/end2end/tests/empty_batch.c \
+    test/core/end2end/tests/filter_call_init_fails.c \
     test/core/end2end/tests/filter_causes_close.c \
     test/core/end2end/tests/graceful_server_shutdown.c \
     test/core/end2end/tests/high_initial_seqno.c \
@@ -6541,6 +6845,7 @@
     test/core/end2end/tests/idempotent_request.c \
     test/core/end2end/tests/invoke_large_request.c \
     test/core/end2end/tests/large_metadata.c \
+    test/core/end2end/tests/load_reporting_hook.c \
     test/core/end2end/tests/max_concurrent_streams.c \
     test/core/end2end/tests/max_message_length.c \
     test/core/end2end/tests/negative_deadline.c \
@@ -6570,7 +6875,7 @@
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
-	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBEND2END_NOSEC_TESTS_OBJS) 
+	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBEND2END_NOSEC_TESTS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib -no_warning_for_no_symbols $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
 endif
@@ -6875,6 +7180,38 @@
 endif
 
 
+CENSUS_RESOURCE_TEST_SRC = \
+    test/core/census/resource_test.c \
+
+CENSUS_RESOURCE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CENSUS_RESOURCE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/census_resource_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/census_resource_test: $(CENSUS_RESOURCE_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) $(CENSUS_RESOURCE_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)/census_resource_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/census/resource_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_census_resource_test: $(CENSUS_RESOURCE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CENSUS_RESOURCE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CHANNEL_CREATE_TEST_SRC = \
     test/core/surface/channel_create_test.c \
 
@@ -10044,7 +10381,7 @@
 
 
 TIMEOUT_ENCODING_TEST_SRC = \
-    test/core/transport/chttp2/timeout_encoding_test.c \
+    test/core/transport/timeout_encoding_test.c \
 
 TIMEOUT_ENCODING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TIMEOUT_ENCODING_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
@@ -10064,7 +10401,7 @@
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/transport/chttp2/timeout_encoding_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/transport/timeout_encoding_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_timeout_encoding_test: $(TIMEOUT_ENCODING_TEST_OBJS:.o=.dep)
 
@@ -11012,6 +11349,49 @@
 endif
 
 
+FILTER_END2END_TEST_SRC = \
+    test/cpp/end2end/filter_end2end_test.cc \
+
+FILTER_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(FILTER_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/filter_end2end_test: 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)/filter_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/filter_end2end_test: $(PROTOBUF_DEP) $(FILTER_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(FILTER_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/filter_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/filter_end2end_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_filter_end2end_test: $(FILTER_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(FILTER_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GENERIC_END2END_TEST_SRC = \
     test/cpp/end2end/generic_end2end_test.cc \
 
@@ -11125,16 +11505,16 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_cli.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 
 deps_grpc_cli: $(GRPC_CLI_OBJS:.o=.dep)
 
@@ -11331,6 +11711,60 @@
 endif
 
 
+GRPC_TOOL_TEST_SRC = \
+    $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
+    $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
+    test/cpp/util/grpc_tool_test.cc \
+    test/cpp/util/string_ref_helper.cc \
+
+GRPC_TOOL_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_TOOL_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpc_tool_test: 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)/grpc_tool_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpc_tool_test: $(PROTOBUF_DEP) $(GRPC_TOOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_TOOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_tool_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/echo.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/testing/echo_messages.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_tool_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o:  $(LIBDIR)/$(CONFIG)/libgrpc_cli_libs.a $(LIBDIR)/$(CONFIG)/libgrpc++_reflection.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_grpc_tool_test: $(GRPC_TOOL_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPC_TOOL_TEST_OBJS:.o=.dep)
+endif
+endif
+$(OBJDIR)/$(CONFIG)/test/cpp/util/grpc_tool_test.o: $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc
+
+
 GRPCLB_API_TEST_SRC = \
     $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
     test/cpp/grpclb/grpclb_api_test.cc \
@@ -11378,6 +11812,53 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_api_test.o: $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc
 
 
+GRPCLB_TEST_SRC = \
+    $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.pb.cc $(GENDIR)/src/proto/grpc/lb/v1/load_balancer.grpc.pb.cc \
+    test/cpp/grpclb/grpclb_test.cc \
+
+GRPCLB_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPCLB_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/grpclb_test: 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)/grpclb_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/grpclb_test: $(PROTOBUF_DEP) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPCLB_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpclb_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/src/proto/grpc/lb/v1/load_balancer.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+
+$(OBJDIR)/$(CONFIG)/test/cpp/grpclb/grpclb_test.o:  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
+
+deps_grpclb_test: $(GRPCLB_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GRPCLB_TEST_OBJS:.o=.dep)
+endif
+endif
+$(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
+
+
 HYBRID_END2END_TEST_SRC = \
     test/cpp/end2end/hybrid_end2end_test.cc \
 
@@ -11471,10 +11952,10 @@
 
 else
 
-$(BINDIR)/$(CONFIG)/interop_server:  $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+$(BINDIR)/$(CONFIG)/interop_server:  $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/interop_server
+	$(Q) $(LDXX) $(LDFLAGS)  $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/interop_server
 
 endif
 
@@ -14052,34 +14533,34 @@
 endif
 
 
-H2_LOADREPORTING_TEST_SRC = \
-    test/core/end2end/fixtures/h2_loadreporting.c \
+H2_LOAD_REPORTING_TEST_SRC = \
+    test/core/end2end/fixtures/h2_load_reporting.c \
 
-H2_LOADREPORTING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_LOADREPORTING_TEST_SRC))))
+H2_LOAD_REPORTING_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_LOAD_REPORTING_TEST_SRC))))
 ifeq ($(NO_SECURE),true)
 
 # You can't build secure targets if you don't have OpenSSL.
 
-$(BINDIR)/$(CONFIG)/h2_loadreporting_test: openssl_dep_error
+$(BINDIR)/$(CONFIG)/h2_load_reporting_test: openssl_dep_error
 
 else
 
 
 
-$(BINDIR)/$(CONFIG)/h2_loadreporting_test: $(H2_LOADREPORTING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/h2_load_reporting_test: $(H2_LOAD_REPORTING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(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) $(H2_LOADREPORTING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(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)/h2_loadreporting_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_LOAD_REPORTING_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(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)/h2_load_reporting_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_loadreporting.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_load_reporting.o:  $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
-deps_h2_loadreporting_test: $(H2_LOADREPORTING_TEST_OBJS:.o=.dep)
+deps_h2_load_reporting_test: $(H2_LOAD_REPORTING_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_SECURE),true)
 ifneq ($(NO_DEPS),true)
--include $(H2_LOADREPORTING_TEST_OBJS:.o=.dep)
+-include $(H2_LOAD_REPORTING_TEST_OBJS:.o=.dep)
 endif
 endif
 
@@ -14492,23 +14973,23 @@
 endif
 
 
-H2_LOADREPORTING_NOSEC_TEST_SRC = \
-    test/core/end2end/fixtures/h2_loadreporting.c \
+H2_LOAD_REPORTING_NOSEC_TEST_SRC = \
+    test/core/end2end/fixtures/h2_load_reporting.c \
 
-H2_LOADREPORTING_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_LOADREPORTING_NOSEC_TEST_SRC))))
+H2_LOAD_REPORTING_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_LOAD_REPORTING_NOSEC_TEST_SRC))))
 
 
-$(BINDIR)/$(CONFIG)/h2_loadreporting_nosec_test: $(H2_LOADREPORTING_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/h2_load_reporting_nosec_test: $(H2_LOAD_REPORTING_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(H2_LOADREPORTING_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_loadreporting_nosec_test
+	$(Q) $(LD) $(LDFLAGS) $(H2_LOAD_REPORTING_NOSEC_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/h2_load_reporting_nosec_test
 
-$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_loadreporting.o:  $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_load_reporting.o:  $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
-deps_h2_loadreporting_nosec_test: $(H2_LOADREPORTING_NOSEC_TEST_OBJS:.o=.dep)
+deps_h2_load_reporting_nosec_test: $(H2_LOAD_REPORTING_NOSEC_TEST_OBJS:.o=.dep)
 
 ifneq ($(NO_DEPS),true)
--include $(H2_LOADREPORTING_NOSEC_TEST_OBJS:.o=.dep)
+-include $(H2_LOAD_REPORTING_NOSEC_TEST_OBJS:.o=.dep)
 endif
 
 
@@ -15032,6 +15513,7 @@
 test/cpp/interop/client_helper.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)
 test/cpp/interop/server_helper.cc: $(OPENSSL_DEP)
 test/cpp/qps/client_async.cc: $(OPENSSL_DEP)
 test/cpp/qps/client_sync.cc: $(OPENSSL_DEP)
@@ -15046,8 +15528,11 @@
 test/cpp/util/benchmark_config.cc: $(OPENSSL_DEP)
 test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP)
 test/cpp/util/cli_call.cc: $(OPENSSL_DEP)
+test/cpp/util/cli_credentials.cc: $(OPENSSL_DEP)
 test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP)
+test/cpp/util/grpc_tool.cc: $(OPENSSL_DEP)
 test/cpp/util/proto_file_parser.cc: $(OPENSSL_DEP)
+test/cpp/util/proto_reflection_descriptor_database.cc: $(OPENSSL_DEP)
 test/cpp/util/string_ref_helper.cc: $(OPENSSL_DEP)
 test/cpp/util/subprocess.cc: $(OPENSSL_DEP)
 test/cpp/util/test_config.cc: $(OPENSSL_DEP)
diff --git a/binding.gyp b/binding.gyp
index e1130ad..17dbfc0 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -568,6 +568,7 @@
         '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/handshaker.c',
         'src/core/lib/channel/http_client_filter.c',
         'src/core/lib/channel/http_server_filter.c',
         'src/core/lib/compression/compression.c',
@@ -648,6 +649,7 @@
         'src/core/lib/transport/metadata.c',
         'src/core/lib/transport/metadata_batch.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',
@@ -670,7 +672,6 @@
         '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/timeout_encoding.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',
@@ -726,6 +727,7 @@
         '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',
@@ -737,6 +739,7 @@
         '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/grpc_context.c',
@@ -746,6 +749,7 @@
         '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/tracing.c',
         'src/core/plugin_registry/grpc_plugin_registry.c',
       ],
diff --git a/build.yaml b/build.yaml
index 8377c65..506a029 100644
--- a/build.yaml
+++ b/build.yaml
@@ -7,20 +7,23 @@
   '#3': Use "-preN" suffixes to identify pre-release versions
   '#4': Per-language overrides are possible with (eg) ruby_version tag here
   '#5': See the expand_version.py for all the quirks here
-  version: 1.0.1-pre1
+  version: 1.1.0-dev
 filegroups:
 - name: census
   public_headers:
   - include/grpc/census.h
   headers:
   - 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/grpc_filter.h
   - src/core/ext/census/mlog.h
+  - src/core/ext/census/resource.h
   - src/core/ext/census/rpc_metric_id.h
   src:
+  - 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/grpc_context.c
@@ -30,6 +33,7 @@
   - 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/tracing.c
   plugin: census_grpc_plugin
   uses:
@@ -157,6 +161,7 @@
   - src/core/lib/channel/compress_filter.h
   - src/core/lib/channel/connected_channel.h
   - src/core/lib/channel/context.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/compression/algorithm_metadata.h
@@ -227,6 +232,7 @@
   - src/core/lib/transport/metadata.h
   - src/core/lib/transport/metadata_batch.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:
@@ -235,6 +241,7 @@
   - 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/handshaker.c
   - src/core/lib/channel/http_client_filter.c
   - src/core/lib/channel/http_server_filter.c
   - src/core/lib/compression/compression.c
@@ -315,6 +322,7 @@
   - src/core/lib/transport/metadata.c
   - src/core/lib/transport/metadata_batch.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
   deps:
@@ -375,11 +383,14 @@
   - gpr_codegen
 - name: grpc_lb_policy_grpclb
   headers:
+  - 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:
+  - 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
+  plugin: grpc_lb_policy_grpclb
   uses:
   - grpc_base
   - grpc_client_config
@@ -527,7 +538,6 @@
   - 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/timeout_encoding.h
   - src/core/ext/transport/chttp2/transport/varint.h
   src:
   - src/core/ext/transport/chttp2/transport/bin_decoder.c
@@ -549,7 +559,6 @@
   - 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/timeout_encoding.c
   - src/core/ext/transport/chttp2/transport/varint.c
   - src/core/ext/transport/chttp2/transport/writing.c
   plugin: grpc_chttp2_plugin
@@ -683,6 +692,7 @@
   - include/grpc++/support/time.h
   headers:
   - 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:
@@ -695,6 +705,7 @@
   - src/cpp/client/generic_stub.cc
   - src/cpp/client/insecure_credentials.cc
   - src/cpp/common/channel_arguments.cc
+  - src/cpp/common/channel_filter.cc
   - src/cpp/common/completion_queue.cc
   - src/cpp/common/core_codegen.cc
   - src/cpp/common/rpc_method.cc
@@ -767,6 +778,23 @@
   language: c++
   public_headers:
   - include/grpc++/impl/codegen/config_protobuf.h
+- name: grpc++_reflection_proto
+  language: c++
+  public_headers:
+  - include/grpc++/ext/reflection.grpc.pb.h
+  - include/grpc++/ext/reflection.pb.h
+  src:
+  - src/cpp/ext/reflection.grpc.pb.cc
+  - src/cpp/ext/reflection.pb.cc
+  uses:
+  - grpc++_codegen_proto
+- name: thrift_util
+  language: c++
+  public_headers:
+  - include/grpc++/impl/codegen/thrift_serializer.h
+  - include/grpc++/impl/codegen/thrift_utils.h
+  uses:
+  - grpc++_codegen_base
 libs:
 - name: gpr
   build: all
@@ -869,6 +897,7 @@
   - grpc
   filegroups:
   - grpc_test_util_base
+  - grpc_base
   vs_project_guid: '{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}'
 - name: grpc_test_util_unsecure
   build: private
@@ -959,19 +988,20 @@
   language: c++
   public_headers:
   - include/grpc++/ext/proto_server_reflection_plugin.h
-  - include/grpc++/ext/reflection.grpc.pb.h
-  - include/grpc++/ext/reflection.pb.h
   headers:
   - src/cpp/ext/proto_server_reflection.h
   src:
   - src/cpp/ext/proto_server_reflection.cc
   - src/cpp/ext/proto_server_reflection_plugin.cc
-  - src/cpp/ext/reflection.grpc.pb.cc
-  - src/cpp/ext/reflection.pb.cc
   deps:
   - grpc++
   filegroups:
-  - grpc++_codegen_proto
+  - grpc++_reflection_proto
+- name: grpc++_reflection_codegen
+  build: private
+  language: c++
+  src:
+  - src/proto/grpc/reflection/v1alpha/reflection.proto
 - name: grpc++_test_config
   build: private
   language: c++
@@ -1007,6 +1037,7 @@
   - grpc++_codegen_base_src
   - grpc++_codegen_proto
   - grpc++_config_proto
+  - thrift_util
 - name: grpc++_unsecure
   build: all
   language: c++
@@ -1028,13 +1059,21 @@
   language: c++
   headers:
   - test/cpp/util/cli_call.h
+  - test/cpp/util/cli_credentials.h
+  - test/cpp/util/config_grpc_cli.h
+  - test/cpp/util/grpc_tool.h
   - test/cpp/util/proto_file_parser.h
+  - test/cpp/util/proto_reflection_descriptor_database.h
   src:
   - test/cpp/util/cli_call.cc
+  - test/cpp/util/cli_credentials.cc
+  - test/cpp/util/grpc_tool.cc
   - test/cpp/util/proto_file_parser.cc
+  - test/cpp/util/proto_reflection_descriptor_database.cc
   deps:
+  - grpc++_reflection
   - grpc++
-  - grpc_plugin_support
+  - grpc++_test_config
 - name: grpc_plugin_support
   build: protoc
   language: c++
@@ -1113,7 +1152,7 @@
   - grpc++
   - grpc
   - gpr
-- name: interop_server_main
+- name: interop_server_lib
   build: private
   language: c++
   src:
@@ -1130,6 +1169,13 @@
   - gpr_test_util
   - gpr
   - grpc++_test_config
+- name: interop_server_main
+  build: private
+  language: c++
+  src:
+  - test/cpp/interop/interop_server_bootstrap.cc
+  deps:
+  - interop_server_lib
 - name: qps
   build: private
   language: c++
@@ -1278,6 +1324,16 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: census_resource_test
+  build: test
+  language: c
+  src:
+  - test/core/census/resource_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: channel_create_test
   build: test
   language: c
@@ -2332,7 +2388,7 @@
   build: test
   language: c
   src:
-  - test/core/transport/chttp2/timeout_encoding_test.c
+  - test/core/transport/timeout_encoding_test.c
   deps:
   - grpc_test_util
   - grpc
@@ -2622,6 +2678,19 @@
   - grpc
   - gpr_test_util
   - gpr
+- name: filter_end2end_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/cpp/end2end/filter_end2end_test.cc
+  deps:
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: generic_end2end_test
   gtest: true
   build: test
@@ -2654,11 +2723,9 @@
   - test/cpp/util/grpc_cli.cc
   deps:
   - grpc_cli_libs
-  - grpc++_test_util
-  - grpc_test_util
+  - grpc++_reflection
   - grpc++
   - grpc
-  - gpr_test_util
   - gpr
   - grpc++_test_config
 - name: grpc_cpp_plugin
@@ -2720,6 +2787,28 @@
   secure: false
   vs_config_type: Application
   vs_project_guid: '{069E9D05-B78B-4751-9252-D21EBAE7DE8E}'
+- name: grpc_tool_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - test/cpp/util/string_ref_helper.h
+  src:
+  - src/proto/grpc/testing/echo.proto
+  - src/proto/grpc/testing/echo_messages.proto
+  - test/cpp/util/grpc_tool_test.cc
+  - test/cpp/util/string_ref_helper.cc
+  deps:
+  - grpc_cli_libs
+  - grpc++_reflection
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  filegroups:
+  - grpc++_codegen_proto
+  - grpc++_config_proto
 - name: grpclb_api_test
   gtest: true
   build: test
@@ -2732,6 +2821,20 @@
   - grpc_test_util
   - grpc++
   - grpc
+- name: grpclb_test
+  gtest: false
+  build: test
+  language: c++
+  src:
+  - src/proto/grpc/lb/v1/load_balancer.proto
+  - test/cpp/grpclb/grpclb_test.cc
+  deps:
+  - gpr
+  - gpr_test_util
+  - grpc
+  - grpc++
+  - grpc++_test_util
+  - grpc_test_util
 - name: hybrid_end2end_test
   gtest: true
   build: test
@@ -2772,6 +2875,7 @@
   deps:
   - interop_server_main
   - interop_server_helper
+  - interop_server_lib
   - grpc++_test_util
   - grpc_test_util
   - grpc++
diff --git a/config.m4 b/config.m4
index 0c3322d..b37658d 100644
--- a/config.m4
+++ b/config.m4
@@ -87,6 +87,7 @@
     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/handshaker.c \
     src/core/lib/channel/http_client_filter.c \
     src/core/lib/channel/http_server_filter.c \
     src/core/lib/compression/compression.c \
@@ -167,6 +168,7 @@
     src/core/lib/transport/metadata.c \
     src/core/lib/transport/metadata_batch.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 \
@@ -189,7 +191,6 @@
     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/timeout_encoding.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 \
@@ -245,6 +246,7 @@
     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 \
@@ -256,6 +258,7 @@
     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/grpc_context.c \
@@ -265,6 +268,7 @@
     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/tracing.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
     src/boringssl/err_data.c \
diff --git a/doc/c-style-guide.md b/doc/c-style-guide.md
index d6f9bbd..369bd56 100644
--- a/doc/c-style-guide.md
+++ b/doc/c-style-guide.md
@@ -9,16 +9,17 @@
 General
 -------
 
-- Layout rules are defined by clang-format, and all code should be passed through
-  clang-format. A (docker-based) script to do so is included in 
-  [tools/distrib/clang\_format\_code.sh] (../tools/distrib/clang_format_code.sh).
+- Layout rules are defined by clang-format, and all code should be passed
+  through clang-format. A (docker-based) script to do so is included in
+  [tools/distrib/clang\_format\_code.sh](../tools/distrib/clang_format_code.sh).
 
 Header Files
 ------------
 
-- Public header files (those in the include/grpc tree) should compile as pedantic C89
-- Public header files should be includable from C++ programs. That is, they should 
-  include the following:
+- Public header files (those in the include/grpc tree) should compile as
+  pedantic C89.
+- Public header files should be includable from C++ programs. That is, they
+  should include the following:
   ```c
   #ifdef __cplusplus
   extern "C" {
@@ -34,24 +35,34 @@
 - All header files should have a #define guard to prevent multiple inclusion.
   To guarantee uniqueness they should be based on the file's path.
 
-  For public headers: include/grpc/grpc.h --> GRPC_GRPC_H
+  For public headers: `include/grpc/grpc.h` → `GRPC_GRPC_H`
 
-  For private headers: 
-  src/core/channel/channel_stack.h --> GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H
+  For private headers:
+  `src/core/channel/channel_stack.h` →
+  `GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_STACK_H`
+
+Variable Initialization
+-----------------------
+
+When declaring a (non-static) pointer variable, always initialize it to `NULL`.
+Even in the case of static pointer variables, it's recommended to explicitly
+initialize them to `NULL`.
+
 
 C99 Features
 ------------
 
-- Variable sized arrays are not allowed
-- Do not use the 'inline' keyword
-- Flexible array members are allowed (https://en.wikipedia.org/wiki/Flexible_array_member)
+- Variable sized arrays are not allowed.
+- Do not use the 'inline' keyword.
+- Flexible array members are allowed
+  (https://en.wikipedia.org/wiki/Flexible_array_member).
 
 Comments
 --------
 
 Within public header files, only `/* */` comments are allowed.
 
-Within implementation files and private headers, either single line `//` 
+Within implementation files and private headers, either single line `//`
 or multi line `/* */` comments are allowed. Only one comment style per file is
 allowed however (i.e. if single line comments are used anywhere within a file,
 ALL comments within that file must be single line comments).
@@ -59,7 +70,15 @@
 Symbol Names
 ------------
 
-- Non-static functions must be prefixed by grpc_
-- static functions must not be prefixed by grpc_
-- enumeration values and #define names are uppercased, all others are lowercased
-- Multiple word identifiers use underscore as a delimiter (NEVER camel casing)
+- Non-static functions must be prefixed by `grpc_`
+- Static functions must *not* be prefixed by `grpc_`
+- Enumeration values and `#define` names must be uppercase. All other values
+  must be lowercase.
+- Multiple word identifiers use underscore as a delimiter, *never* camel
+  case. E.g. `variable_name`.
+
+Functions
+----------
+
+- The use of [`atexit()`](http://man7.org/linux/man-pages/man3/atexit.3.html) is
+  in forbidden in libgrpc.
diff --git a/doc/command_line_tool.md b/doc/command_line_tool.md
index 89a7054..79a131c 100644
--- a/doc/command_line_tool.md
+++ b/doc/command_line_tool.md
@@ -15,6 +15,7 @@
 - Send unary rpc.
 - Attach metadata and display received metadata.
 - Handle common authentication to server.
+- Infer request/response types from server reflection result.
 - Find the request/response types from a given proto file.
 - Read proto request in text form.
 - Read request in wire form (for protobuf messages, this means serialized binary form).
@@ -24,7 +25,6 @@
 The command line tool should support the following things:
 
 - List server services and methods through server reflection.
-- Infer request/response types from server reflection result.
 - Fine-grained auth control (such as, use this oauth token to talk to the server).
 - Send streaming rpc.
 
@@ -46,24 +46,35 @@
 Send a rpc to a helloworld server at `localhost:50051`:
 
 ```
-$ bins/opt/grpc_cli call localhost:50051 SayHello examples/protos/helloworld.proto \
-    "name: 'world'"  --enable_ssl=false
+$ bins/opt/grpc_cli call localhost:50051 SayHello "name: 'world'" \
+    --enable_ssl=false
 ```
 
 On success, the tool will print out
 
 ```
 Rpc succeeded with OK status
-Response: 
+Response:
  message: "Hello world"
 ```
 
 The `localhost:50051` part indicates the server you are connecting to. `SayHello` is (part of) the
-gRPC method string. Then there is the path to the proto file containing the service definition,
-if it is not under current directory, you can use `--proto_path` to specify a new search root.
-`"name: 'world'"` is the text format of the request proto message. 
-We are not using ssl here by `--enable_ssl=false`. For information on more
-flags, look at the comments of `grpc_cli.cc`.
+gRPC method string. Then `"name: 'world'"` is the text format of the request proto message. We are
+not using ssl here by `--enable_ssl=false`. For information on more flags, look at the comments of `grpc_cli.cc`.
+
+### Use local proto files
+
+If the server does not have the server reflection service, you will need to provide local proto
+files containing the service definition. The tool will try to find request/response types from
+them.
+
+```
+$ bins/opt/grpc_cli call localhost:50051 SayHello "name: 'world'" \
+    --protofiles=examples/protos/helloworld.proto --enable_ssl=false
+```
+
+If the proto files is not under current directory, you can use `--proto_path` to specify a new
+search root.
 
 ### Send non-proto rpc
 
diff --git a/doc/health-checking.md b/doc/health-checking.md
index 92512e9..7be8107 100644
--- a/doc/health-checking.md
+++ b/doc/health-checking.md
@@ -58,7 +58,7 @@
 set to `SERVING` or `NOT_SERVING` accordingly. If the service name is not
 registered, the server returns a `NOT_FOUND` GRPC status.
 
-The server should use an empty string as the key for server’s
+The server should use an empty string as the key for server's
 overall health status, so that a client not interested in a specific service can
 query the server's status with an empty request. The server can just do exact
 matching of the service name without support of any kind of wildcard matching.
diff --git a/doc/images/load_balancing_design.png b/doc/images/load_balancing_design.png
new file mode 100644
index 0000000..8618396
--- /dev/null
+++ b/doc/images/load_balancing_design.png
Binary files differ
diff --git a/doc/load-balancing.md b/doc/load-balancing.md
index 681be02..dfaa7a7 100644
--- a/doc/load-balancing.md
+++ b/doc/load-balancing.md
@@ -4,7 +4,7 @@
 # Objective
 
 To design a load balancing API between a gRPC client and a Load Balancer to
-instruct the client how to send load to multiple backend servers. 
+instruct the client how to send load to multiple backend servers.
 
 # Background
 
@@ -19,7 +19,7 @@
 latency to the RPCs.
 
 The proxy model was deemed inefficient when considering request heavy services
-like storage. 
+like storage.
 
 ### Balancing-aware Client
 
@@ -28,7 +28,7 @@
 Random, etc) used to select servers from a list. In this model, a list of
 servers would be either statically configured in the client, provided by the
 name resolution system, an external load balancer, etc. In any case, the client
-is responsible for choosing the preferred server from the list. 
+is responsible for choosing the preferred server from the list.
 
 One of the drawbacks of this approach is writing and maintaining the load
 balancing policies in multiple languages and/or versions of the clients. These
@@ -53,14 +53,69 @@
 complex decisions and inform the client. The load balancer may communicate with
 the backend servers to collect load and health information.
 
+
+## Requirements
+
+#### Simple API and client
+
+The gRPC client load balancing code must be simple and portable. The client
+should only contain simple algorithms (ie Round Robin) for server selection. For
+complex algorithms, the client should rely on a load balancer to provide load
+balancing configuration and the list of servers to which the client should send
+requests. The balancer will update the server list as needed to balance the load
+as well as handle server unavailability or health issues. The load balancer will
+make any necessary complex decisions and inform the client. The load balancer
+may communicate with the backend servers to collect load and health information.
+
+#### Security
+
+The load balancer may be separate from the actual server backends and a
+compromise of the load balancer should only lead to a compromise of the
+loadbalancing functionality. In other words, a compromised load balancer should
+not be able to cause a client to trust a (potentially malicious) backend server
+any more than in a comparable situation without loadbalancing.
+
 # Proposed Architecture
 
-The gRPC load balancing approach follows the third approach, by having an
-external load balancer which provides simple clients with a list of servers.
+The gRPC load balancing implements the external load balancing server approach:
+an external load balancer provides simple clients with an up-to-date list of
+servers.
+
+![image](images/load_balancing_design.png)
+
+1. On startup, the gRPC client issues a name resolution request for the service.
+   The name will resolve to one or more IP addresses to gRPC servers, a hint on
+   whether the IP address(es) point to a load balancer or not, and also return a
+   client config.
+2. The gRPC client connects to a gRPC Server.
+   1. If the name resolution has hinted that the endpoint is a load balancer,
+      the client's gRPC LB policy will attempt to open a stream to the load
+      balancer service. The server may respond in only one of the following
+      ways.
+      1. `status::UNIMPLEMENTED`. There is no loadbalancing in use. The client
+         call will fail.
+      2. "I am a Load Balancer and here is the server list." (Goto Step 4.)
+      3. "Please contact Load Balancer X" (See Step 3.) The client will close
+         this connection and cancel the stream.
+      4. If the server fails to respond, the client will wait for some timeout
+         and then re-resolve the name (process to Step 1 above).
+   2. If the name resolution has not hinted that the endpoint is a load
+      balancer, the client connects directly to the service it wants to talk to.
+3. The gRPC client's gRPC LB policy opens a separate connection to the Load
+   Balancer. If this fails, it will go back to step 1 and try another address.
+   1. During channel initialization to the Load Balancer, the client will
+      attempt to open a stream to the Load Balancer service.
+   2. The Load Balancer will return a server list to the gRPC client. If the
+      server list is empty, the call will wait until a non-empty one is
+      received. Optional: The Load Balancer will also open channels to the gRPC
+      servers if load reporting is needed.
+4. The gRPC client will send RPCs to the gRPC servers contained in the server
+   list from the Load Balancer.
+5. Optional: The gRPC servers may periodically report load to the Load Balancer.
 
 ## Client
 
-When establishing a gRPC stream to the balancer, the client will send an initial
+When establishing a gRPC _stream_ to the balancer, the client will send an initial
 request to the load balancer (via a regular gRPC message). The load balancer
 will respond with client config (including, for example, settings for flow
 control, RPC deadlines, etc.) or a redirect to another load balancer. If the
@@ -87,11 +142,3 @@
 The gRPC Server is responsible for answering RPC requests and providing
 responses to the client. The server will also report load to the load balancer
 if a reporting stream was opened for this purpose.
-
-### Security 
-
-The load balancer may be separate from the actual server backends and a
-compromise of the load balancer should only lead to a compromise of the
-loadbalancing functionality. In other words, a compromised load balancer should
-not be able to cause a client to trust a (potentially malicious) backend server
-any more than in a comparable situation without loadbalancing. 
diff --git a/doc/statuscodes.md b/doc/statuscodes.md
index c918f9e..1cd72df 100644
--- a/doc/statuscodes.md
+++ b/doc/statuscodes.md
@@ -18,6 +18,7 @@
 | Could not decompress, but compression algorithm supported (Server -> Client)	| INTERNAL | Client |
 | Compression mechanism used by client not supported at server	| UNIMPLEMENTED | Server |
 | Server temporarily out of resources (e.g., Flow-control resource limits reached) |	RESOURCE_EXHAUSTED | Server|
+| Client does not have enough memory to hold the server response | RESOURCE_EXHAUSTED | Client |
 | Flow-control protocol violation |	INTERNAL | Both |
 | Error parsing returned status	| UNKNOWN | Client |
 | Incorrect Auth metadata ( Credentials failed to get metadata, Incompatible credentials set on channel and call, Invalid host set in `:authority` metadata, etc.) | UNAUTHENTICATED | Both |
diff --git a/examples/cpp/helloworld/CMakeLists.txt b/examples/cpp/helloworld/CMakeLists.txt
new file mode 100644
index 0000000..8f098c9
--- /dev/null
+++ b/examples/cpp/helloworld/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Minimum CMake required

+cmake_minimum_required(VERSION 2.8)

+

+# Project

+project(HelloWorld CXX)

+

+# Protobuf

+set(protobuf_MODULE_COMPATIBLE TRUE)

+find_package(protobuf CONFIG REQUIRED)

+message(STATUS "Using protobuf ${protobuf_VERSION}")

+

+# gRPC

+find_package(gRPC CONFIG REQUIRED)

+message(STATUS "Using gRPC ${gRPC_VERSION}")

+

+# gRPC C++ plugin

+get_target_property(gRPC_CPP_PLUGIN_EXECUTABLE gRPC::grpc_cpp_plugin

+    IMPORTED_LOCATION_RELEASE)

+

+# Proto file

+get_filename_component(hw_proto "../../protos/helloworld.proto" ABSOLUTE)

+get_filename_component(hw_proto_path "${hw_proto}" PATH)

+

+# Generated sources

+protobuf_generate_cpp(hw_proto_srcs hw_proto_hdrs "${hw_proto}")

+set(hw_grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.cc")

+set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h")

+add_custom_command(

+      OUTPUT "${hw_grpc_srcs}" "${hw_grpc_hdrs}"

+      COMMAND protobuf::protoc

+      ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" -I "${hw_proto_path}"

+        --plugin=protoc-gen-grpc="${gRPC_CPP_PLUGIN_EXECUTABLE}"

+        "${hw_proto}"

+      DEPENDS "${hw_proto}")

+

+# Generated include directory

+include_directories("${CMAKE_CURRENT_BINARY_DIR}")

+

+# Targets greeter_[async_](client|server)

+foreach(_target

+  greeter_client greeter_server

+  greeter_async_client greeter_async_server)

+  add_executable(${_target} "${_target}.cc"

+    ${hw_proto_srcs}

+    ${hw_grpc_srcs})

+  target_link_libraries(${_target}

+    protobuf::libprotobuf

+    gRPC::grpc++_unsecure)

+endforeach()

diff --git a/examples/cpp/helloworld/Makefile b/examples/cpp/helloworld/Makefile
index bfb78e0..2c50b82 100644
--- a/examples/cpp/helloworld/Makefile
+++ b/examples/cpp/helloworld/Makefile
@@ -29,12 +29,20 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
+HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
+SYSTEM ?= $(HOST_SYSTEM)
 CXX = g++
 CPPFLAGS += -I/usr/local/include -pthread
 CXXFLAGS += -std=c++11
+ifeq ($(SYSTEM),Darwin)
+LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++ grpc`       \
+           -lgrpc++_reflection \
+           -lprotobuf -lpthread -ldl
+else
 LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++ grpc`       \
            -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \
            -lprotobuf -lpthread -ldl
+endif
 PROTOC = protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
 GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
diff --git a/examples/cpp/route_guide/Makefile b/examples/cpp/route_guide/Makefile
index 3ce089c..00cf9ad 100644
--- a/examples/cpp/route_guide/Makefile
+++ b/examples/cpp/route_guide/Makefile
@@ -29,12 +29,20 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 
+HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
+SYSTEM ?= $(HOST_SYSTEM)
 CXX = g++
 CPPFLAGS += -I/usr/local/include -pthread
 CXXFLAGS += -std=c++11
+ifeq ($(SYSTEM),Darwin)
+LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++`            \
+           -lgrpc++_reflection \
+           -lprotobuf -lpthread -ldl
+else
 LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++`            \
            -Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed \
            -lprotobuf -lpthread -ldl
+endif
 PROTOC = protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
 GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index b8dd2a7..86b811a 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -101,6 +101,8 @@
     'ALWAYS_SEARCH_USER_PATHS' => 'NO',
   }
 
+  s.default_subspecs = 'Interface', 'Implementation'
+
   # Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
   # sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't
   # allow any header to be listed outside the `header_mappings_dir` (even though doing so works in
@@ -256,6 +258,7 @@
                       'src/core/lib/channel/compress_filter.h',
                       'src/core/lib/channel/connected_channel.h',
                       'src/core/lib/channel/context.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/compression/algorithm_metadata.h',
@@ -326,6 +329,7 @@
                       'src/core/lib/transport/metadata.h',
                       'src/core/lib/transport/metadata_batch.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',
@@ -347,7 +351,6 @@
                       '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/timeout_encoding.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',
@@ -390,6 +393,7 @@
                       'src/core/ext/client_config/subchannel_call_holder.h',
                       'src/core/ext/client_config/subchannel_index.h',
                       'src/core/ext/client_config/uri_parser.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',
@@ -399,11 +403,13 @@
                       '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/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/lib/surface/init.c',
                       'src/core/lib/channel/channel_args.c',
@@ -411,6 +417,7 @@
                       '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/handshaker.c',
                       'src/core/lib/channel/http_client_filter.c',
                       'src/core/lib/channel/http_server_filter.c',
                       'src/core/lib/compression/compression.c',
@@ -491,6 +498,7 @@
                       'src/core/lib/transport/metadata.c',
                       'src/core/lib/transport/metadata_batch.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',
@@ -513,7 +521,6 @@
                       '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/timeout_encoding.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',
@@ -569,6 +576,7 @@
                       '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',
@@ -580,6 +588,7 @@
                       '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/grpc_context.c',
@@ -589,6 +598,7 @@
                       '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/tracing.c',
                       'src/core/plugin_registry/grpc_plugin_registry.c'
 
@@ -609,6 +619,7 @@
                               'src/core/lib/channel/compress_filter.h',
                               'src/core/lib/channel/connected_channel.h',
                               'src/core/lib/channel/context.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/compression/algorithm_metadata.h',
@@ -679,6 +690,7 @@
                               'src/core/lib/transport/metadata.h',
                               'src/core/lib/transport/metadata_batch.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',
@@ -700,7 +712,6 @@
                               '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/timeout_encoding.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',
@@ -743,6 +754,7 @@
                               'src/core/ext/client_config/subchannel_call_holder.h',
                               'src/core/ext/client_config/subchannel_index.h',
                               'src/core/ext/client_config/uri_parser.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',
@@ -752,11 +764,39 @@
                               '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/grpc_filter.h',
                               'src/core/ext/census/mlog.h',
+                              'src/core/ext/census/resource.h',
                               'src/core/ext/census/rpc_metric_id.h'
   end
+
+  s.subspec 'Cronet-Interface' do |ss|
+    ss.header_mappings_dir = 'include/grpc'
+    ss.source_files = 'include/grpc/grpc_cronet.h'
+  end
+
+  s.subspec 'Cronet-Implementation' do |ss|
+    ss.header_mappings_dir = '.'
+    ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
+                      'src/core/ext/transport/cronet/transport/cronet_transport.c'
+  end
+
+  s.subspec 'Tests' do |ss|
+    ss.header_mappings_dir = '.'
+
+    ss.source_files = 'test/core/end2end/cq_verifier.{c,h}',
+                      'test/core/end2end/end2end_tests.{c,h}',
+                      'test/core/end2end/tests/*.{c,h}',
+                      'test/core/end2end/data/*.{c,h}',
+                      'test/core/util/test_config.{c,h}',
+                      'test/core/util/port.h',
+                      'test/core/util/port_posix.c',
+                      'test/core/util/port_server_client.{c,h}'
+
+    ss.dependency 'CronetFramework'
+  end
 end
diff --git a/grpc.def b/grpc.def
index 0849f84..e2255df 100644
--- a/grpc.def
+++ b/grpc.def
@@ -23,15 +23,10 @@
     census_trace_scan_start
     census_get_trace_record
     census_trace_scan_end
+    census_define_resource
+    census_delete_resource
+    census_resource_id
     census_record_values
-    census_view_create
-    census_view_delete
-    census_view_metric
-    census_view_naggregations
-    census_view_tags
-    census_view_aggregrations
-    census_view_get_data
-    census_view_reset
     grpc_compression_algorithm_parse
     grpc_compression_algorithm_name
     grpc_compression_algorithm_for_level
@@ -148,6 +143,7 @@
     gpr_slice_ref
     gpr_slice_unref
     gpr_slice_new
+    gpr_slice_new_with_user_data
     gpr_slice_new_with_len
     gpr_slice_malloc
     gpr_slice_from_copied_string
diff --git a/grpc.gemspec b/grpc.gemspec
index 59c27fd..8d74e36 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -177,6 +177,7 @@
   s.files += %w( src/core/lib/channel/compress_filter.h )
   s.files += %w( src/core/lib/channel/connected_channel.h )
   s.files += %w( src/core/lib/channel/context.h )
+  s.files += %w( src/core/lib/channel/handshaker.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/compression/algorithm_metadata.h )
@@ -247,6 +248,7 @@
   s.files += %w( src/core/lib/transport/metadata.h )
   s.files += %w( src/core/lib/transport/metadata_batch.h )
   s.files += %w( src/core/lib/transport/static_metadata.h )
+  s.files += %w( src/core/lib/transport/timeout_encoding.h )
   s.files += %w( src/core/lib/transport/transport.h )
   s.files += %w( src/core/lib/transport/transport_impl.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/bin_decoder.h )
@@ -268,7 +270,6 @@
   s.files += %w( src/core/ext/transport/chttp2/transport/internal.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/status_conversion.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.h )
-  s.files += %w( src/core/ext/transport/chttp2/transport/timeout_encoding.h )
   s.files += %w( src/core/ext/transport/chttp2/transport/varint.h )
   s.files += %w( src/core/ext/transport/chttp2/alpn/alpn.h )
   s.files += %w( src/core/lib/security/context/security_context.h )
@@ -311,6 +312,7 @@
   s.files += %w( src/core/ext/client_config/subchannel_call_holder.h )
   s.files += %w( src/core/ext/client_config/subchannel_index.h )
   s.files += %w( src/core/ext/client_config/uri_parser.h )
+  s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.h )
   s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.h )
   s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h )
   s.files += %w( third_party/nanopb/pb.h )
@@ -320,11 +322,13 @@
   s.files += %w( src/core/ext/load_reporting/load_reporting.h )
   s.files += %w( src/core/ext/load_reporting/load_reporting_filter.h )
   s.files += %w( src/core/ext/census/aggregation.h )
+  s.files += %w( src/core/ext/census/base_resources.h )
   s.files += %w( src/core/ext/census/census_interface.h )
   s.files += %w( src/core/ext/census/census_rpc_stats.h )
   s.files += %w( src/core/ext/census/gen/census.pb.h )
   s.files += %w( src/core/ext/census/grpc_filter.h )
   s.files += %w( src/core/ext/census/mlog.h )
+  s.files += %w( src/core/ext/census/resource.h )
   s.files += %w( src/core/ext/census/rpc_metric_id.h )
   s.files += %w( src/core/lib/surface/init.c )
   s.files += %w( src/core/lib/channel/channel_args.c )
@@ -332,6 +336,7 @@
   s.files += %w( src/core/lib/channel/channel_stack_builder.c )
   s.files += %w( src/core/lib/channel/compress_filter.c )
   s.files += %w( src/core/lib/channel/connected_channel.c )
+  s.files += %w( src/core/lib/channel/handshaker.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/compression/compression.c )
@@ -412,6 +417,7 @@
   s.files += %w( src/core/lib/transport/metadata.c )
   s.files += %w( src/core/lib/transport/metadata_batch.c )
   s.files += %w( src/core/lib/transport/static_metadata.c )
+  s.files += %w( src/core/lib/transport/timeout_encoding.c )
   s.files += %w( src/core/lib/transport/transport.c )
   s.files += %w( src/core/lib/transport/transport_op_string.c )
   s.files += %w( src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c )
@@ -434,7 +440,6 @@
   s.files += %w( src/core/ext/transport/chttp2/transport/status_conversion.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/stream_lists.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/stream_map.c )
-  s.files += %w( src/core/ext/transport/chttp2/transport/timeout_encoding.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/varint.c )
   s.files += %w( src/core/ext/transport/chttp2/transport/writing.c )
   s.files += %w( src/core/ext/transport/chttp2/alpn/alpn.c )
@@ -490,6 +495,7 @@
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c )
   s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )
   s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c )
+  s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.c )
   s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.c )
   s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c )
   s.files += %w( third_party/nanopb/pb_common.c )
@@ -501,6 +507,7 @@
   s.files += %w( src/core/ext/resolver/sockaddr/sockaddr_resolver.c )
   s.files += %w( src/core/ext/load_reporting/load_reporting.c )
   s.files += %w( src/core/ext/load_reporting/load_reporting_filter.c )
+  s.files += %w( src/core/ext/census/base_resources.c )
   s.files += %w( src/core/ext/census/context.c )
   s.files += %w( src/core/ext/census/gen/census.pb.c )
   s.files += %w( src/core/ext/census/grpc_context.c )
@@ -510,6 +517,7 @@
   s.files += %w( src/core/ext/census/mlog.c )
   s.files += %w( src/core/ext/census/operation.c )
   s.files += %w( src/core/ext/census/placeholders.c )
+  s.files += %w( src/core/ext/census/resource.c )
   s.files += %w( src/core/ext/census/tracing.c )
   s.files += %w( src/core/plugin_registry/grpc_plugin_registry.c )
   s.files += %w( third_party/boringssl/crypto/aes/internal.h )
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index 544dace..5ceab73 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -65,7 +65,7 @@
                             const W& request)
       : context_(context),
         call_(channel->CreateCall(method, context, cq)),
-        collection_(new CallOpSetCollection) {
+        collection_(std::make_shared<CallOpSetCollection>()) {
     collection_->init_buf_.SetCollection(collection_);
     collection_->init_buf_.SendInitialMetadata(
         context->send_initial_metadata_, context->initial_metadata_flags());
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
index a132c9a..012bcc2 100644
--- a/include/grpc++/impl/codegen/client_context.h
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -41,7 +41,7 @@
 ///
 /// Context settings are only relevant to the call they are invoked with, that
 /// is to say, they aren't sticky. Some of these settings, such as the
-/// compression options, can be made persistant at channel construction time
+/// compression options, can be made persistent at channel construction time
 /// (see \a grpc::CreateCustomChannel).
 ///
 /// \warning ClientContext instances should \em not be reused across rpcs.
diff --git a/include/grpc++/impl/codegen/config_protobuf.h b/include/grpc++/impl/codegen/config_protobuf.h
index 4bee1bc..8620d4b 100644
--- a/include/grpc++/impl/codegen/config_protobuf.h
+++ b/include/grpc++/impl/codegen/config_protobuf.h
@@ -40,16 +40,21 @@
 #endif
 
 #ifndef GRPC_CUSTOM_MESSAGE
+#ifdef GRPC_USE_PROTO_LITE
+#include <google/protobuf/message_lite.h>
+#define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite
+#else
 #include <google/protobuf/message.h>
 #define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
 #endif
+#endif
 
 #ifndef GRPC_CUSTOM_DESCRIPTOR
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
 #define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor
 #define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool
-#define GPRC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
+#define GRPC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor
 #define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor
 #define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto
 #define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor
@@ -57,6 +62,13 @@
 #define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation
 #endif
 
+#ifndef GRPC_CUSTOM_DESCRIPTORDATABASE
+#include <google/protobuf/descriptor_database.h>
+#define GRPC_CUSTOM_DESCRIPTORDATABASE ::google::protobuf::DescriptorDatabase
+#define GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE \
+  ::google::protobuf::SimpleDescriptorDatabase
+#endif
+
 #ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
 #include <google/protobuf/io/coded_stream.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -75,11 +87,13 @@
 
 typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
 typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool;
-typedef GPRC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
+typedef GRPC_CUSTOM_DESCRIPTORDATABASE DescriptorDatabase;
+typedef GRPC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor;
 typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor;
 typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto;
 typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor;
 typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor;
+typedef GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE SimpleDescriptorDatabase;
 typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation;
 
 namespace io {
diff --git a/include/grpc++/impl/codegen/core_codegen.h b/include/grpc++/impl/codegen/core_codegen.h
index 9699abf..2586b94 100644
--- a/include/grpc++/impl/codegen/core_codegen.h
+++ b/include/grpc++/impl/codegen/core_codegen.h
@@ -31,6 +31,9 @@
  *
  */
 
+#ifndef GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_H
+#define GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_H
+
 // This file should be compiled as part of grpc++.
 
 #include <grpc++/impl/codegen/core_codegen_interface.h>
@@ -83,3 +86,5 @@
 };
 
 }  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CORE_CODEGEN_H
diff --git a/include/grpc++/impl/codegen/impl/async_stream.h b/include/grpc++/impl/codegen/impl/async_stream.h
deleted file mode 100644
index 7d7a956..0000000
--- a/include/grpc++/impl/codegen/impl/async_stream.h
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- *
- * 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.
- *
- */
-
-#ifndef GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
-#define GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
-
-#include <grpc++/impl/codegen/call.h>
-#include <grpc++/impl/codegen/channel_interface.h>
-#include <grpc++/impl/codegen/core_codegen_interface.h>
-#include <grpc++/impl/codegen/server_context.h>
-#include <grpc++/impl/codegen/service_type.h>
-#include <grpc++/impl/codegen/status.h>
-
-namespace grpc {
-
-class CompletionQueue;
-
-/// Common interface for all client side asynchronous streaming.
-class ClientAsyncStreamingInterface {
- public:
-  virtual ~ClientAsyncStreamingInterface() {}
-
-  /// Request notification of the reading of the initial metadata. Completion
-  /// will be notified by \a tag on the associated completion queue.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  virtual void ReadInitialMetadata(void* tag) = 0;
-
-  /// Request notification completion.
-  ///
-  /// \param[out] status To be updated with the operation status.
-  /// \param[in] tag Tag identifying this request.
-  virtual void Finish(Status* status, void* tag) = 0;
-};
-
-/// An interface that yields a sequence of messages of type \a R.
-template <class R>
-class AsyncReaderInterface {
- public:
-  virtual ~AsyncReaderInterface() {}
-
-  /// Read a message of type \a R into \a msg. Completion will be notified by \a
-  /// tag on the associated completion queue.
-  ///
-  /// \param[out] msg Where to eventually store the read message.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void Read(R* msg, void* tag) = 0;
-};
-
-/// An interface that can be fed a sequence of messages of type \a W.
-template <class W>
-class AsyncWriterInterface {
- public:
-  virtual ~AsyncWriterInterface() {}
-
-  /// Request the writing of \a msg with identifying tag \a tag.
-  ///
-  /// Only one write may be outstanding at any given time. This means that
-  /// after calling Write, one must wait to receive \a tag from the completion
-  /// queue BEFORE calling Write again.
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void Write(const W& msg, void* tag) = 0;
-};
-
-template <class R>
-class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface,
-                                   public AsyncReaderInterface<R> {};
-
-template <class R>
-class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> {
- public:
-  /// Create a stream and write the first request out.
-  template <class W>
-  ClientAsyncReader(ChannelInterface* channel, CompletionQueue* cq,
-                    const RpcMethod& method, ClientContext* context,
-                    const W& request, void* tag)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_ops_.set_output_tag(tag);
-    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok());
-    init_ops_.ClientSendClose();
-    call_.PerformOps(&init_ops_);
-  }
-
-  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      read_ops_.RecvInitialMetadata(context_);
-    }
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
-      init_ops_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
-};
-
-/// Common interface for client side asynchronous writing.
-template <class W>
-class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface,
-                                   public AsyncWriterInterface<W> {
- public:
-  /// Signal the client is done with the writes.
-  ///
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WritesDone(void* tag) = 0;
-};
-
-template <class W>
-class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> {
- public:
-  template <class R>
-  ClientAsyncWriter(ChannelInterface* channel, CompletionQueue* cq,
-                    const RpcMethod& method, ClientContext* context,
-                    R* response, void* tag)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    finish_ops_.RecvMessage(response);
-
-    init_ops_.set_output_tag(tag);
-    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
-    call_.PerformOps(&init_ops_);
-  }
-
-  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void WritesDone(void* tag) GRPC_OVERRIDE {
-    writes_done_ops_.set_output_tag(tag);
-    writes_done_ops_.ClientSendClose();
-    call_.PerformOps(&writes_done_ops_);
-  }
-
-  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  CallOpSet<CallOpSendInitialMetadata> init_ops_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
-  CallOpSet<CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpClientSendClose> writes_done_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
-            CallOpClientRecvStatus>
-      finish_ops_;
-};
-
-/// Client-side interface for asynchronous bi-directional streaming.
-template <class W, class R>
-class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface,
-                                         public AsyncWriterInterface<W>,
-                                         public AsyncReaderInterface<R> {
- public:
-  /// Signal the client is done with the writes.
-  ///
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WritesDone(void* tag) = 0;
-};
-
-template <class W, class R>
-class ClientAsyncReaderWriter GRPC_FINAL
-    : public ClientAsyncReaderWriterInterface<W, R> {
- public:
-  ClientAsyncReaderWriter(ChannelInterface* channel, CompletionQueue* cq,
-                          const RpcMethod& method, ClientContext* context,
-                          void* tag)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_ops_.set_output_tag(tag);
-    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
-    call_.PerformOps(&init_ops_);
-  }
-
-  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      read_ops_.RecvInitialMetadata(context_);
-    }
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void WritesDone(void* tag) GRPC_OVERRIDE {
-    writes_done_ops_.set_output_tag(tag);
-    writes_done_ops_.ClientSendClose();
-    call_.PerformOps(&writes_done_ops_);
-  }
-
-  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  CallOpSet<CallOpSendInitialMetadata> init_ops_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpClientSendClose> writes_done_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
-};
-
-template <class W, class R>
-class ServerAsyncReaderInterface : public ServerAsyncStreamingInterface,
-                                   public AsyncReaderInterface<R> {
- public:
-  virtual void Finish(const W& msg, const Status& status, void* tag) = 0;
-
-  virtual void FinishWithError(const Status& status, void* tag) = 0;
-};
-
-template <class W, class R>
-class ServerAsyncReader GRPC_FINAL : public ServerAsyncReaderInterface<W, R> {
- public:
-  explicit ServerAsyncReader(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Finish(const W& msg, const Status& status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // The response is dropped if the status is not OK.
-    if (status.ok()) {
-      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
-                                   finish_ops_.SendMessage(msg));
-    } else {
-      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    }
-    call_.PerformOps(&finish_ops_);
-  }
-
-  void FinishWithError(const Status& status, void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!status.ok());
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-            CallOpServerSendStatus>
-      finish_ops_;
-};
-
-template <class W>
-class ServerAsyncWriterInterface : public ServerAsyncStreamingInterface,
-                                   public AsyncWriterInterface<W> {
- public:
-  virtual void Finish(const Status& status, void* tag) = 0;
-};
-
-template <class W>
-class ServerAsyncWriter GRPC_FINAL : public ServerAsyncWriterInterface<W> {
- public:
-  explicit ServerAsyncWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Finish(const Status& status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
-};
-
-/// Server-side interface for asynchronous bi-directional streaming.
-template <class W, class R>
-class ServerAsyncReaderWriterInterface : public ServerAsyncStreamingInterface,
-                                         public AsyncWriterInterface<W>,
-                                         public AsyncReaderInterface<R> {
- public:
-  virtual void Finish(const Status& status, void* tag) = 0;
-};
-
-template <class W, class R>
-class ServerAsyncReaderWriter GRPC_FINAL
-    : public ServerAsyncReaderWriterInterface<W, R> {
- public:
-  explicit ServerAsyncReaderWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // TODO(ctiller): don't assert
-    GPR_CODEGEN_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Finish(const Status& status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  friend class ::grpc::Server;
-
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
-};
-
-}  // namespace grpc
-
-#endif  // GRPCXX_IMPL_CODEGEN_IMPL_ASYNC_STREAM_H
diff --git a/include/grpc++/impl/codegen/thrift_serializer.h b/include/grpc++/impl/codegen/thrift_serializer.h
new file mode 100644
index 0000000..7308a15
--- /dev/null
+++ b/include/grpc++/impl/codegen/thrift_serializer.h
@@ -0,0 +1,219 @@
+/*
+ *
+ * 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 GRPCXX_IMPL_CODEGEN_THRIFT_SERIALIZER_H
+#define GRPCXX_IMPL_CODEGEN_THRIFT_SERIALIZER_H
+
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/byte_buffer_reader.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <thrift/protocol/TBinaryProtocol.h>
+#include <thrift/protocol/TCompactProtocol.h>
+#include <thrift/protocol/TProtocolException.h>
+#include <thrift/transport/TBufferTransports.h>
+#include <thrift/transport/TTransportUtils.h>
+#include <boost/make_shared.hpp>
+#include <memory>
+#include <stdexcept>
+#include <string>
+
+namespace apache {
+namespace thrift {
+namespace util {
+
+using apache::thrift::protocol::TBinaryProtocolT;
+using apache::thrift::protocol::TCompactProtocolT;
+using apache::thrift::protocol::TMessageType;
+using apache::thrift::protocol::TNetworkBigEndian;
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::transport::TBufferBase;
+using apache::thrift::transport::TTransport;
+
+template <typename Dummy, typename Protocol>
+class ThriftSerializer {
+ public:
+  ThriftSerializer()
+      : prepared_(false),
+        last_deserialized_(false),
+        serialize_version_(false) {}
+
+  virtual ~ThriftSerializer() {}
+
+  // Serialize the passed type into the internal buffer
+  // and returns a pointer to internal buffer and its size
+  template <typename T>
+  void Serialize(const T& fields, const uint8_t** serialized_buffer,
+                 size_t* serialized_len) {
+    // prepare or reset buffer
+    if (!prepared_ || last_deserialized_) {
+      prepare();
+    } else {
+      buffer_->resetBuffer();
+    }
+    last_deserialized_ = false;
+
+    // if required serialize protocol version
+    if (serialize_version_) {
+      protocol_->writeMessageBegin("", TMessageType(0), 0);
+    }
+
+    // serialize fields into buffer
+    fields.write(protocol_.get());
+
+    // write the end of message
+    if (serialize_version_) {
+      protocol_->writeMessageEnd();
+    }
+
+    uint8_t* byte_buffer;
+    uint32_t byte_buffer_size;
+    buffer_->getBuffer(&byte_buffer, &byte_buffer_size);
+    *serialized_buffer = byte_buffer;
+    *serialized_len = byte_buffer_size;
+  }
+
+  // Serialize the passed type into the byte buffer
+  template <typename T>
+  void Serialize(const T& fields, grpc_byte_buffer** bp) {
+    const uint8_t* byte_buffer;
+    size_t byte_buffer_size;
+
+    Serialize(fields, &byte_buffer, &byte_buffer_size);
+
+    gpr_slice slice = gpr_slice_from_copied_buffer(
+        reinterpret_cast<const char*>(byte_buffer), byte_buffer_size);
+
+    *bp = grpc_raw_byte_buffer_create(&slice, 1);
+
+    gpr_slice_unref(slice);
+  }
+
+  // Deserialize the passed char array into  the passed type, returns the number
+  // of bytes that have been consumed from the passed string.
+  template <typename T>
+  uint32_t Deserialize(uint8_t* serialized_buffer, size_t length, T* fields) {
+    // prepare buffer if necessary
+    if (!prepared_) {
+      prepare();
+    }
+    last_deserialized_ = true;
+
+    // reset buffer transport
+    buffer_->resetBuffer(serialized_buffer, length);
+
+    // read the protocol version if necessary
+    if (serialize_version_) {
+      std::string name = "";
+      TMessageType mt = static_cast<TMessageType>(0);
+      int32_t seq_id = 0;
+      protocol_->readMessageBegin(name, mt, seq_id);
+    }
+
+    // deserialize buffer into fields
+    uint32_t len = fields->read(protocol_.get());
+
+    // read the end of message
+    if (serialize_version_) {
+      protocol_->readMessageEnd();
+    }
+
+    return len;
+  }
+
+  // Deserialize the passed byte buffer to passed type, returns the number
+  // of bytes consumed from byte buffer
+  template <typename T>
+  uint32_t Deserialize(grpc_byte_buffer* buffer, T* msg) {
+    grpc_byte_buffer_reader reader;
+    grpc_byte_buffer_reader_init(&reader, buffer);
+
+    gpr_slice slice = grpc_byte_buffer_reader_readall(&reader);
+
+    uint32_t len =
+        Deserialize(GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice), msg);
+
+    gpr_slice_unref(slice);
+
+    grpc_byte_buffer_reader_destroy(&reader);
+
+    return len;
+  }
+
+  // set serialization version flag
+  void SetSerializeVersion(bool value) { serialize_version_ = value; }
+
+  // Set the container size limit to deserialize
+  // This function should be called after buffer_ is initialized
+  void SetContainerSizeLimit(int32_t container_limit) {
+    if (!prepared_) {
+      prepare();
+    }
+    protocol_->setContainerSizeLimit(container_limit);
+  }
+
+  // Set the string size limit to deserialize
+  // This function should be called after buffer_ is initialized
+  void SetStringSizeLimit(int32_t string_limit) {
+    if (!prepared_) {
+      prepare();
+    }
+    protocol_->setStringSizeLimit(string_limit);
+  }
+
+ private:
+  bool prepared_;
+  bool last_deserialized_;
+  boost::shared_ptr<TMemoryBuffer> buffer_;
+  std::shared_ptr<Protocol> protocol_;
+  bool serialize_version_;
+
+  void prepare() {
+    buffer_ = boost::make_shared<TMemoryBuffer>();
+    // create a protocol for the memory buffer transport
+    protocol_ = std::make_shared<Protocol>(buffer_);
+    prepared_ = true;
+  }
+
+};  // ThriftSerializer
+
+typedef ThriftSerializer<void, TBinaryProtocolT<TBufferBase, TNetworkBigEndian>>
+    ThriftSerializerBinary;
+typedef ThriftSerializer<void, TCompactProtocolT<TBufferBase>>
+    ThriftSerializerCompact;
+
+}  // namespace util
+}  // namespace thrift
+}  // namespace apache
+
+#endif
\ No newline at end of file
diff --git a/include/grpc++/impl/codegen/thrift_utils.h b/include/grpc++/impl/codegen/thrift_utils.h
new file mode 100644
index 0000000..7d19b24
--- /dev/null
+++ b/include/grpc++/impl/codegen/thrift_utils.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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 GRPCXX_IMPL_CODEGEN_THRIFT_UTILS_H
+#define GRPCXX_IMPL_CODEGEN_THRIFT_UTILS_H
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/core_codegen_interface.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/status_code_enum.h>
+#include <grpc++/impl/codegen/thrift_serializer.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/byte_buffer_reader.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <cstdint>
+#include <cstdlib>
+
+namespace grpc {
+
+using apache::thrift::util::ThriftSerializerCompact;
+
+template <class T>
+class SerializationTraits<T, typename std::enable_if<std::is_base_of<
+                                 apache::thrift::TBase, T>::value>::type> {
+ public:
+  static Status Serialize(const T& msg, grpc_byte_buffer** bp,
+                          bool* own_buffer) {
+    *own_buffer = true;
+
+    ThriftSerializerCompact serializer;
+    serializer.Serialize(msg, bp);
+
+    return Status(StatusCode::OK, "ok");
+  }
+
+  static Status Deserialize(grpc_byte_buffer* buffer, T* msg,
+                            int max_message_size) {
+    if (!buffer) {
+      return Status(StatusCode::INTERNAL, "No payload");
+    }
+
+    ThriftSerializerCompact deserializer;
+    deserializer.Deserialize(buffer, msg);
+
+    grpc_byte_buffer_destroy(buffer);
+
+    return Status(StatusCode::OK, "ok");
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_THRIFT_UTILS_H
diff --git a/include/grpc++/support/byte_buffer.h b/include/grpc++/support/byte_buffer.h
index 20bd407..01249a0 100644
--- a/include/grpc++/support/byte_buffer.h
+++ b/include/grpc++/support/byte_buffer.h
@@ -72,6 +72,9 @@
   /// Buffer size in bytes.
   size_t Length() const;
 
+  /// Swap the state of *this and *other.
+  void Swap(ByteBuffer* other);
+
  private:
   friend class SerializationTraits<ByteBuffer, void>;
 
diff --git a/include/grpc++/support/slice.h b/include/grpc++/support/slice.h
index cec9062..5874b4f 100644
--- a/include/grpc++/support/slice.h
+++ b/include/grpc++/support/slice.h
@@ -77,6 +77,9 @@
   /// Raw pointer to the end (one byte \em past the last element) of the slice.
   const uint8_t* end() const { return GPR_SLICE_END_PTR(slice_); }
 
+  /// Raw C slice. Caller needs to call gpr_slice_unref when done.
+  gpr_slice c_slice() const { return gpr_slice_ref(slice_); }
+
  private:
   friend class ByteBuffer;
 
diff --git a/include/grpc/census.h b/include/grpc/census.h
index 39d87ba..62ff45d 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -56,9 +56,11 @@
 
 /** Shutdown and startup census subsystem. The 'features' argument should be
  * the OR (|) of census_features values. If census fails to initialize, then
- * census_initialize() will return a non-zero value. It is an error to call
- * census_initialize() more than once (without an intervening
- * census_shutdown()). */
+ * census_initialize() will return -1, otherwise the set of enabled features
+ * (which may be smaller than that provided in the `features` argument, see
+ * census_supported()) is returned. It is an error to call census_initialize()
+ * more than once (without an intervening census_shutdown()). These functions
+ * are not thread-safe. */
 CENSUSAPI int census_initialize(int features);
 CENSUSAPI void census_shutdown(void);
 
@@ -430,30 +432,44 @@
 CENSUSAPI void census_trace_scan_end();
 
 /* Core stats collection API's. The following concepts are used:
-   * Aggregation: A collection of values. Census supports the following
-       aggregation types:
-         Sum - a single summation type. Typically used for keeping (e.g.)
-           counts of events.
-         Distribution - statistical distribution information, used for
-           recording average, standard deviation etc.
-         Histogram - a histogram of measurements falling in defined bucket
-           boundaries.
-         Window - a count of events that happen in reolling time window.
-     New aggregation types can be added by the user, if desired (see
-     census_register_aggregation()).
-   * Metric: Each measurement is for a single metric. Examples include RPC
-     latency, CPU seconds consumed, and bytes transmitted.
-   * View: A view is a combination of a metric, a tag set (in which the tag
-     values are regular expressions) and a set of aggregations. When a
-     measurement for a metric matches the view tags, it is recorded (for each
-     unique set of tags) against each aggregation. Each metric can have an
-     arbitrary number of views by which it will be broken down.
+   * Resource: Users record measurements for a single resource. Examples
+     include RPC latency, CPU seconds consumed, and bytes transmitted.
+   * Aggregation: An aggregation of a set of measurements. Census supports the
+       following aggregation types:
+       * Distribution - statistical distribution information, used for
+         recording average, standard deviation etc. Can include a histogram.
+       * Interval - a count of events that happen in a rolling time window.
+   * View: A view is a combination of a Resource, a set of tag keys and an
+     Aggregation. When a measurement for a Resource matches the View tags, it is
+     recorded (for each unique set of tag values) using the Aggregation type.
+     Each resource can have an arbitrary number of views by which it will be
+     broken down.
+
+  Census uses protos to define each of the above, and output results. This
+  ensures unification across the different language and runtime
+  implementations. The proto definitions can be found in src/proto/census.
 */
 
+/* Define a new resource. `resource_pb` should contain an encoded Resource
+   protobuf, `resource_pb_size` being the size of the buffer. Returns a -ve
+   value on error, or a positive (>= 0) resource id (for use in
+   census_delete_resource() and census_record_values()). In order to be valid, a
+   resource must have a name, and at least one numerator in it's unit type. The
+   resource name must be unique, and an error will be returned if it is not. */
+CENSUSAPI int32_t census_define_resource(const uint8_t *resource_pb,
+                                         size_t resource_pb_size);
+
+/* Delete a resource created by census_define_resource(). */
+CENSUSAPI void census_delete_resource(int32_t resource_id);
+
+/* Determine the id of a resource, given it's name. returns -1 if the resource
+   does not exist. */
+CENSUSAPI int32_t census_resource_id(const char *name);
+
 /* A single value to be recorded comprises two parts: an ID for the particular
- * metric and the value to be recorded against it. */
+ * resource and the value to be recorded against it. */
 typedef struct {
-  uint32_t metric_id;
+  int32_t resource_id;
   double value;
 } census_value;
 
@@ -461,78 +477,6 @@
 CENSUSAPI void census_record_values(census_context *context,
                                     census_value *values, size_t nvalues);
 
-/** Type representing a particular aggregation */
-typedef struct census_aggregation_ops census_aggregation_ops;
-
-/* Predefined aggregation types, for use with census_view_create(). */
-extern census_aggregation_ops census_agg_sum;
-extern census_aggregation_ops census_agg_distribution;
-extern census_aggregation_ops census_agg_histogram;
-extern census_aggregation_ops census_agg_window;
-
-/** Information needed to instantiate a new aggregation. Used in view
-    construction via census_define_view(). */
-typedef struct {
-  const census_aggregation_ops *ops;
-  const void *create_arg; /* Aaggregation initialization argument. */
-} census_aggregation;
-
-/** A census view type. Opaque. */
-typedef struct census_view census_view;
-
-/** Create a new view.
-  @param metric_id Metric with which this view is associated.
-  @param tags tags that define the view.
-  @param aggregations aggregations to associate with the view
-  @param naggregations number of aggregations
-
-  @return A new census view
-*/
-
-/* TODO(aveitch): consider if context is the right argument type to pass in
-   tags. */
-CENSUSAPI census_view *census_view_create(
-    uint32_t metric_id, const census_context *tags,
-    const census_aggregation *aggregations, size_t naggregations);
-
-/** Destroy a previously created view. */
-CENSUSAPI void census_view_delete(census_view *view);
-
-/** Metric ID associated with a view */
-CENSUSAPI size_t census_view_metric(const census_view *view);
-
-/** Number of aggregations associated with view. */
-CENSUSAPI size_t census_view_naggregations(const census_view *view);
-
-/** Get tags associated with view. */
-CENSUSAPI const census_context *census_view_tags(const census_view *view);
-
-/** Get aggregation descriptors associated with a view. */
-CENSUSAPI const census_aggregation *census_view_aggregrations(
-    const census_view *view);
-
-/** Holds all the aggregation data for a particular view instantiation. Forms
-  part of the data returned by census_view_data(). */
-typedef struct {
-  const census_context *tags; /* Tags for this set of aggregations. */
-  const void **data; /* One data set for every aggregation in the view. */
-} census_view_aggregation_data;
-
-/** Census view data as returned by census_view_get_data(). */
-typedef struct {
-  size_t n_tag_sets; /* Number of unique tag sets that matched view. */
-  const census_view_aggregation_data *data; /* n_tag_sets entries */
-} census_view_data;
-
-/** Get data from aggregations associated with a view.
-  @param view View from which to get data.
-  @return Full set of data for all aggregations for the view.
-*/
-CENSUSAPI const census_view_data *census_view_get_data(const census_view *view);
-
-/** Reset all view data to zero for the specified view */
-CENSUSAPI void census_view_reset(census_view *view);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 6f7a67b..4ca018e 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -170,8 +170,9 @@
     completions are sent to 'completion_queue'. 'method' and 'host' need only
     live through the invocation of this function.
     If parent_call is non-NULL, it must be a server-side call. It will be used
-    to propagate properties from the server call to this new client call.
-    */
+    to propagate 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). */
 GRPCAPI grpc_call *grpc_channel_create_call(
     grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
     grpc_completion_queue *completion_queue, const char *method,
@@ -187,7 +188,8 @@
                                          const char *method, const char *host,
                                          void *reserved);
 
-/** Create a call given a handle returned from grpc_channel_register_call */
+/** Create a call given a handle returned from grpc_channel_register_call.
+    \sa grpc_channel_create_call. */
 GRPCAPI grpc_call *grpc_channel_create_registered_call(
     grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
     grpc_completion_queue *completion_queue, void *registered_call_handle,
diff --git a/include/grpc/impl/codegen/slice.h b/include/grpc/impl/codegen/slice.h
index c684b75..dfc0a77 100644
--- a/include/grpc/impl/codegen/slice.h
+++ b/include/grpc/impl/codegen/slice.h
@@ -120,6 +120,14 @@
    passed in at destruction. */
 GPRAPI gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *));
 
+/* Equivalent to gpr_slice_new, but with a separate pointer that is
+   passed to the destroy function.  This function can be useful when
+   the data is part of a larger structure that must be destroyed when
+   the data is no longer needed. */
+GPRAPI gpr_slice gpr_slice_new_with_user_data(void *p, size_t len,
+                                              void (*destroy)(void *),
+                                              void *user_data);
+
 /* Equivalent to gpr_slice_new, but with a two argument destroy function that
    also takes the slice length. */
 GPRAPI gpr_slice gpr_slice_new_with_len(void *p, size_t len,
diff --git a/package.json b/package.json
index 3f2f3f1..9afba31 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "1.0.1-pre1",
+  "version": "1.1.0-dev",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
diff --git a/package.xml b/package.xml
index 81aa5b2..7d431d8 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
  <date>2016-08-09</date>
  <time>16:06:07</time>
  <version>
-  <release>1.0.1</release>
-  <api>1.0.1</api>
+  <release>1.1.0</release>
+  <api>1.1.0</api>
  </version>
  <stability>
   <release>stable</release>
@@ -185,6 +185,7 @@
     <file baseinstalldir="/" name="src/core/lib/channel/compress_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/context.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/handshaker.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/compression/algorithm_metadata.h" role="src" />
@@ -255,6 +256,7 @@
     <file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport_impl.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/bin_decoder.h" role="src" />
@@ -276,7 +278,6 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/status_conversion.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/timeout_encoding.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/alpn/alpn.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/security/context/security_context.h" role="src" />
@@ -319,6 +320,7 @@
     <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_call_holder.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_index.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" />
@@ -328,11 +330,13 @@
     <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/aggregation.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/census/base_resources.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/census_interface.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/census_rpc_stats.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/gen/census.pb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/grpc_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/mlog.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/census/resource.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/rpc_metric_id.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/init.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.c" role="src" />
@@ -340,6 +344,7 @@
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack_builder.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/compress_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/connected_channel.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/channel/handshaker.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/compression/compression.c" role="src" />
@@ -420,6 +425,7 @@
     <file baseinstalldir="/" name="src/core/lib/transport/metadata.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/static_metadata.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/timeout_encoding.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/transport_op_string.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c" role="src" />
@@ -442,7 +448,6 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/status_conversion.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_lists.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/stream_map.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/timeout_encoding.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/varint.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/writing.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/alpn/alpn.c" role="src" />
@@ -498,6 +503,7 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" />
     <file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" />
@@ -509,6 +515,7 @@
     <file baseinstalldir="/" name="src/core/ext/resolver/sockaddr/sockaddr_resolver.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/load_reporting/load_reporting_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/census/base_resources.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/context.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/gen/census.pb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/grpc_context.c" role="src" />
@@ -518,6 +525,7 @@
     <file baseinstalldir="/" name="src/core/ext/census/mlog.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/operation.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/placeholders.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/census/resource.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/tracing.c" role="src" />
     <file baseinstalldir="/" name="src/core/plugin_registry/grpc_plugin_registry.c" role="src" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/aes/internal.h" role="src" />
diff --git a/setup.py b/setup.py
index 096e8bd..f728095 100644
--- a/setup.py
+++ b/setup.py
@@ -69,7 +69,9 @@
 
 # Environment variable to determine whether or not the Cython extension should
 # *use* Cython or use the generated C files. Note that this requires the C files
-# to have been generated by building first *with* Cython support.
+# to have been generated by building first *with* Cython support. Even if this
+# is set to false, if the script detects that the generated `.c` file isn't
+# present, then it will still attempt to use Cython.
 BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
 
 # Environment variable to determine whether or not to enable coverage analysis
@@ -98,7 +100,7 @@
     else:
       EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime64 -D_timeb=__timeb64'
   elif "linux" in sys.platform or "darwin" in sys.platform:
-    EXTRA_ENV_COMPILE_ARGS += ' -fno-wrapv'
+    EXTRA_ENV_COMPILE_ARGS += ' -fvisibility=hidden -fno-wrapv'
 if EXTRA_ENV_LINK_ARGS is None:
   EXTRA_ENV_LINK_ARGS = ''
   if "linux" in sys.platform or "darwin" in sys.platform:
@@ -110,6 +112,8 @@
     EXTRA_ENV_LINK_ARGS += (
         ' -static-libgcc -static-libstdc++ -mcrtdll={msvcr} '
         '-static'.format(msvcr=msvcr))
+  if "linux" in sys.platform:
+    EXTRA_ENV_LINK_ARGS += ' -Wl,-wrap,memcpy'
 
 EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS)
 EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS)
@@ -147,13 +151,10 @@
 
 LDFLAGS = tuple(EXTRA_LINK_ARGS)
 CFLAGS = tuple(EXTRA_COMPILE_ARGS)
-if "linux" in sys.platform:
-  LDFLAGS += ('-Wl,-wrap,memcpy',)
 if "linux" in sys.platform or "darwin" in sys.platform:
-   CFLAGS += ('-fvisibility=hidden',)
-   pymodinit_type = 'PyObject*' if PY3 else 'void'
-   pymodinit = '__attribute__((visibility ("default"))) {}'.format(pymodinit_type)
-   DEFINE_MACROS += (('PyMODINIT_FUNC', pymodinit),)
+  pymodinit_type = 'PyObject*' if PY3 else 'void'
+  pymodinit = '__attribute__((visibility ("default"))) {}'.format(pymodinit_type)
+  DEFINE_MACROS += (('PyMODINIT_FUNC', pymodinit),)
 
 # By default, Python3 distutils enforces compatibility of
 # c plugins (.so files) with the OSX version Python3 was built with.
@@ -168,44 +169,27 @@
         r'macosx-10.7-\1',
         util.get_platform())
 
-
-def cython_extensions(module_names, extra_sources, include_dirs,
-                      libraries, define_macros, build_with_cython=False):
-  # Set compiler directives linetrace argument only if we care about tracing;
-  # this is due to Cython having different behavior between linetrace being
-  # False and linetrace being unset. See issue #5689.
-  cython_compiler_directives = {}
-  if ENABLE_CYTHON_TRACING:
-    define_macros = define_macros + [('CYTHON_TRACE_NOGIL', 1)]
-    cython_compiler_directives['linetrace'] = True
-  file_extension = 'pyx' if build_with_cython else 'c'
-  module_files = [os.path.join(PYTHON_STEM,
-                               name.replace('.', '/') + '.' + file_extension)
-                  for name in module_names]
+def cython_extensions_and_necessity():
+  cython_module_files = [os.path.join(PYTHON_STEM,
+                               name.replace('.', '/') + '.pyx')
+                  for name in CYTHON_EXTENSION_MODULE_NAMES]
   extensions = [
       _extension.Extension(
           name=module_name,
-          sources=[module_file] + extra_sources,
-          include_dirs=include_dirs, libraries=libraries,
-          define_macros=define_macros,
+          sources=[module_file] + list(CYTHON_HELPER_C_FILES) + list(CORE_C_FILES),
+          include_dirs=list(EXTENSION_INCLUDE_DIRECTORIES),
+          libraries=list(EXTENSION_LIBRARIES),
+          define_macros=list(DEFINE_MACROS),
           extra_compile_args=list(CFLAGS),
           extra_link_args=list(LDFLAGS),
-      ) for (module_name, module_file) in zip(module_names, module_files)
+      ) for (module_name, module_file) in zip(list(CYTHON_EXTENSION_MODULE_NAMES), cython_module_files)
   ]
-  if build_with_cython:
-    import Cython.Build
-    return Cython.Build.cythonize(
-        extensions,
-        include_path=include_dirs,
-        compiler_directives=cython_compiler_directives)
-  else:
-    return extensions
+  need_cython = BUILD_WITH_CYTHON
+  if not BUILD_WITH_CYTHON:
+    need_cython = need_cython or not commands.check_and_update_cythonization(extensions)
+  return commands.try_cythonize(extensions, linetracing=ENABLE_CYTHON_TRACING, mandatory=BUILD_WITH_CYTHON), need_cython
 
-CYTHON_EXTENSION_MODULES = cython_extensions(
-    list(CYTHON_EXTENSION_MODULE_NAMES),
-    list(CYTHON_HELPER_C_FILES) + list(CORE_C_FILES),
-    list(EXTENSION_INCLUDE_DIRECTORIES), list(EXTENSION_LIBRARIES),
-    list(DEFINE_MACROS), bool(BUILD_WITH_CYTHON))
+CYTHON_EXTENSION_MODULES, need_cython = cython_extensions_and_necessity()
 
 PACKAGE_DIRECTORIES = {
     '': PYTHON_STEM,
@@ -225,6 +209,15 @@
     'sphinx_rtd_theme>=0.1.8',
     'six>=1.10',
 )
+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/config.h b/src/compiler/config.h
index 1cbd842..ba44cd8 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -60,7 +60,8 @@
 
 #ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER
 #include <google/protobuf/compiler/code_generator.h>
-#define GRPC_CUSTOM_PARSEGENERATORPARAMETER ::google::protobuf::compiler::ParseGeneratorParameter
+#define GRPC_CUSTOM_PARSEGENERATORPARAMETER \
+  ::google::protobuf::compiler::ParseGeneratorParameter
 #endif
 
 #ifndef GRPC_CUSTOM_STRING
@@ -81,8 +82,8 @@
                              const CodeGenerator* generator) {
   return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator);
 }
-static inline void ParseGeneratorParameter(const string& parameter,
-    std::vector<std::pair<string, string> >* options) {
+static inline void ParseGeneratorParameter(
+    const string& parameter, std::vector<std::pair<string, string> >* options) {
   GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options);
 }
 
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 2288ba4..c386115 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -64,19 +64,22 @@
 }
 }  // namespace
 
-template<class T, size_t N>
-T *array_end(T (&array)[N]) { return array + N; }
+template <class T, size_t N>
+T *array_end(T (&array)[N]) {
+  return array + N;
+}
 
-void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, const Parameters &params) {
+void PrintIncludes(Printer *printer, const std::vector<grpc::string> &headers,
+                   const Parameters &params) {
   std::map<grpc::string, grpc::string> vars;
 
   vars["l"] = params.use_system_headers ? '<' : '"';
   vars["r"] = params.use_system_headers ? '>' : '"';
 
-  auto& s = params.grpc_search_path;
+  auto &s = params.grpc_search_path;
   if (!s.empty()) {
     vars["l"] += s;
-    if (s[s.size()-1] != '/') {
+    if (s[s.size() - 1] != '/') {
       vars["l"] += '/';
     }
   }
@@ -101,7 +104,7 @@
 
     printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
     printer->Print(vars,
-                  "// If you make any local change, they will be lost.\n");
+                   "// If you make any local change, they will be lost.\n");
     printer->Print(vars, "// source: $filename$\n");
     grpc::string leading_comments = file->GetLeadingComments();
     if (!leading_comments.empty()) {
@@ -117,8 +120,7 @@
   return output;
 }
 
-grpc::string GetHeaderIncludes(File *file,
-                               const Parameters &params) {
+grpc::string GetHeaderIncludes(File *file, const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -126,15 +128,14 @@
     std::map<grpc::string, grpc::string> vars;
 
     static const char *headers_strs[] = {
-      "grpc++/impl/codegen/async_stream.h",
-      "grpc++/impl/codegen/async_unary_call.h",
-      "grpc++/impl/codegen/proto_utils.h",
-      "grpc++/impl/codegen/rpc_method.h",
-      "grpc++/impl/codegen/service_type.h",
-      "grpc++/impl/codegen/status.h",
-      "grpc++/impl/codegen/stub_options.h",
-      "grpc++/impl/codegen/sync_stream.h"
-    };
+        "grpc++/impl/codegen/async_stream.h",
+        "grpc++/impl/codegen/async_unary_call.h",
+        "grpc++/impl/codegen/proto_utils.h",
+        "grpc++/impl/codegen/rpc_method.h",
+        "grpc++/impl/codegen/service_type.h",
+        "grpc++/impl/codegen/status.h",
+        "grpc++/impl/codegen/stub_options.h",
+        "grpc++/impl/codegen/sync_stream.h"};
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
     PrintIncludes(printer.get(), headers, params);
     printer->Print(vars, "\n");
@@ -309,8 +310,7 @@
   }
 }
 
-void PrintHeaderClientMethod(Printer *printer,
-                             const Method *method,
+void PrintHeaderClientMethod(Printer *printer, const Method *method,
                              std::map<grpc::string, grpc::string> *vars,
                              bool is_public) {
   (*vars)["Method"] = method->name();
@@ -490,10 +490,8 @@
   printer->Print(method->GetTrailingComments().c_str());
 }
 
-void PrintHeaderServerMethodAsync(
-    Printer *printer,
-    const Method *method,
-    std::map<grpc::string, grpc::string> *vars) {
+void PrintHeaderServerMethodAsync(Printer *printer, const Method *method,
+                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
   (*vars)["Response"] = method->output_type_name();
@@ -607,8 +605,7 @@
 }
 
 void PrintHeaderServerMethodGeneric(
-    Printer *printer,
-    const Method *method,
+    Printer *printer, const Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -677,8 +674,7 @@
   printer->Print(*vars, "};\n");
 }
 
-void PrintHeaderService(Printer *printer,
-                        const Service *service,
+void PrintHeaderService(Printer *printer, const Service *service,
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
@@ -696,14 +692,16 @@
   printer->Print("virtual ~StubInterface() {}\n");
   for (int i = 0; i < service->method_count(); ++i) {
     printer->Print(service->method(i)->GetLeadingComments().c_str());
-    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true);
+    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
+                                      true);
     printer->Print(service->method(i)->GetTrailingComments().c_str());
   }
   printer->Outdent();
   printer->Print("private:\n");
   printer->Indent();
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, false);
+    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
+                                      false);
   }
   printer->Outdent();
   printer->Print("};\n");
@@ -711,7 +709,8 @@
       "class Stub GRPC_FINAL : public StubInterface"
       " {\n public:\n");
   printer->Indent();
-  printer->Print("Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
+  printer->Print(
+      "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
   }
@@ -776,8 +775,7 @@
   printer->Print(service->GetTrailingComments().c_str());
 }
 
-grpc::string GetHeaderServices(File *file,
-                               const Parameters &params) {
+grpc::string GetHeaderServices(File *file, const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -849,7 +847,7 @@
 
     printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
     printer->Print(vars,
-                  "// If you make any local change, they will be lost.\n");
+                   "// If you make any local change, they will be lost.\n");
     printer->Print(vars, "// source: $filename$\n\n");
 
     printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
@@ -860,8 +858,7 @@
   return output;
 }
 
-grpc::string GetSourceIncludes(File *file,
-                               const Parameters &params) {
+grpc::string GetSourceIncludes(File *file, const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -869,15 +866,14 @@
     std::map<grpc::string, grpc::string> vars;
 
     static const char *headers_strs[] = {
-      "grpc++/impl/codegen/async_stream.h",
-      "grpc++/impl/codegen/async_unary_call.h",
-      "grpc++/impl/codegen/channel_interface.h",
-      "grpc++/impl/codegen/client_unary_call.h",
-      "grpc++/impl/codegen/method_handler_impl.h",
-      "grpc++/impl/codegen/rpc_service_method.h",
-      "grpc++/impl/codegen/service_type.h",
-      "grpc++/impl/codegen/sync_stream.h"
-    };
+        "grpc++/impl/codegen/async_stream.h",
+        "grpc++/impl/codegen/async_unary_call.h",
+        "grpc++/impl/codegen/channel_interface.h",
+        "grpc++/impl/codegen/client_unary_call.h",
+        "grpc++/impl/codegen/method_handler_impl.h",
+        "grpc++/impl/codegen/rpc_service_method.h",
+        "grpc++/impl/codegen/service_type.h",
+        "grpc++/impl/codegen/sync_stream.h"};
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
     PrintIncludes(printer.get(), headers, params);
 
@@ -895,8 +891,7 @@
   return output;
 }
 
-void PrintSourceClientMethod(Printer *printer,
-                             const Method *method,
+void PrintSourceClientMethod(Printer *printer, const Method *method,
                              std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -996,8 +991,7 @@
   }
 }
 
-void PrintSourceServerMethod(Printer *printer,
-                             const Method *method,
+void PrintSourceServerMethod(Printer *printer, const Method *method,
                              std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -1055,8 +1049,7 @@
   }
 }
 
-void PrintSourceService(Printer *printer,
-                        const Service *service,
+void PrintSourceService(Printer *printer, const Service *service,
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
@@ -1168,8 +1161,7 @@
   }
 }
 
-grpc::string GetSourceServices(File *file,
-                               const Parameters &params) {
+grpc::string GetSourceServices(File *file, const Parameters &params) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index fc0296c..38f8f73 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -48,7 +48,7 @@
 class ProtoBufMethod : public grpc_cpp_generator::Method {
  public:
   ProtoBufMethod(const grpc::protobuf::MethodDescriptor *method)
-    : method_(method) {}
+      : method_(method) {}
 
   grpc::string name() const { return method_->name(); }
 
@@ -90,14 +90,14 @@
 class ProtoBufService : public grpc_cpp_generator::Service {
  public:
   ProtoBufService(const grpc::protobuf::ServiceDescriptor *service)
-    : service_(service) {}
+      : service_(service) {}
 
   grpc::string name() const { return service_->name(); }
 
   int method_count() const { return service_->method_count(); };
   std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
     return std::unique_ptr<const grpc_cpp_generator::Method>(
-          new ProtoBufMethod(service_->method(i)));
+        new ProtoBufMethod(service_->method(i)));
   };
 
   grpc::string GetLeadingComments() const {
@@ -115,7 +115,7 @@
 class ProtoBufPrinter : public grpc_cpp_generator::Printer {
  public:
   ProtoBufPrinter(grpc::string *str)
-    : output_stream_(str), printer_(&output_stream_, '$') {}
+      : output_stream_(str), printer_(&output_stream_, '$') {}
 
   void Print(const std::map<grpc::string, grpc::string> &vars,
              const char *string_template) {
@@ -152,13 +152,14 @@
 
   int service_count() const { return file_->service_count(); };
   std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
-    return std::unique_ptr<const grpc_cpp_generator::Service> (
-          new ProtoBufService(file_->service(i)));
+    return std::unique_ptr<const grpc_cpp_generator::Service>(
+        new ProtoBufService(file_->service(i)));
   }
 
-  std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(grpc::string *str) const {
+  std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(
+      grpc::string *str) const {
     return std::unique_ptr<grpc_cpp_generator::Printer>(
-          new ProtoBufPrinter(str));
+        new ProtoBufPrinter(str));
   }
 
   grpc::string GetLeadingComments() const {
@@ -197,12 +198,11 @@
 
     if (!parameter.empty()) {
       std::vector<grpc::string> parameters_list =
-        grpc_generator::tokenize(parameter, ",");
+          grpc_generator::tokenize(parameter, ",");
       for (auto parameter_string = parameters_list.begin();
-           parameter_string != parameters_list.end();
-           parameter_string++) {
+           parameter_string != parameters_list.end(); parameter_string++) {
         std::vector<grpc::string> param =
-          grpc_generator::tokenize(*parameter_string, "=");
+            grpc_generator::tokenize(*parameter_string, "=");
         if (param[0] == "services_namespace") {
           generator_parameters.services_namespace = param[1];
         } else if (param[0] == "use_system_headers") {
@@ -232,8 +232,7 @@
         grpc_cpp_generator::GetHeaderEpilogue(&pbfile, generator_parameters);
     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
         context->Open(file_name + ".grpc.pb.h"));
-    grpc::protobuf::io::CodedOutputStream header_coded_out(
-        header_output.get());
+    grpc::protobuf::io::CodedOutputStream header_coded_out(header_output.get());
     header_coded_out.WriteRaw(header_code.data(), header_code.size());
 
     grpc::string source_code =
@@ -243,8 +242,7 @@
         grpc_cpp_generator::GetSourceEpilogue(&pbfile, generator_parameters);
     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
         context->Open(file_name + ".grpc.pb.cc"));
-    grpc::protobuf::io::CodedOutputStream source_coded_out(
-        source_output.get());
+    grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get());
     source_coded_out.WriteRaw(source_code.data(), source_code.size());
 
     return true;
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index f5a0876..591e5ae 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -36,11 +36,10 @@
 #include <sstream>
 #include <vector>
 
-#include "src/compiler/csharp_generator.h"
 #include "src/compiler/config.h"
-#include "src/compiler/csharp_generator_helpers.h"
 #include "src/compiler/csharp_generator.h"
-
+#include "src/compiler/csharp_generator.h"
+#include "src/compiler/csharp_generator_helpers.h"
 
 using google::protobuf::compiler::csharp::GetFileNamespace;
 using google::protobuf::compiler::csharp::GetClassName;
@@ -61,7 +60,6 @@
 using std::map;
 using std::vector;
 
-
 namespace grpc_csharp_generator {
 namespace {
 
@@ -70,34 +68,43 @@
 // 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, grpc::protobuf::SourceLocation location) {
-    grpc::string comments = location.leading_comments.empty() ?
-        location.trailing_comments : location.leading_comments;
+void 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;
   }
-  // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+  // XML escaping... no need for apostrophes etc as the whole text is going to
+  // be a child
   // node of a summary element, not part of an attribute.
   comments = grpc_generator::StringReplace(comments, "&", "&amp;", true);
   comments = grpc_generator::StringReplace(comments, "<", "&lt;", true);
 
   std::vector<grpc::string> lines;
   grpc_generator::Split(comments, '\n', &lines);
-  // TODO: We really should work out which part to put in the summary and which to put in the remarks...
-  // but that needs to be part of a bigger effort to understand the markdown better anyway.
+  // TODO: We really should work out which part to put in the summary and which
+  // to put in the remarks...
+  // but that needs to be part of a bigger effort to understand the markdown
+  // better anyway.
   printer->Print("/// <summary>\n");
   bool last_was_empty = false;
-  // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
-  // to preserve the blank lines themselves, as this is relevant in the markdown.
-  // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+  // We squash multiple blank lines down to one, and remove any trailing blank
+  // lines. We need
+  // to preserve the blank lines themselves, as this is relevant in the
+  // markdown.
+  // Note that we can't remove leading or trailing whitespace as *that's*
+  // relevant in markdown too.
   // (We don't skip "just whitespace" lines, either.)
-  for (std::vector<grpc::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+  for (std::vector<grpc::string>::iterator it = lines.begin();
+       it != lines.end(); ++it) {
     grpc::string line = *it;
     if (line.empty()) {
       last_was_empty = true;
     } else {
       if (last_was_empty) {
-          printer->Print("///\n");
+        printer->Print("///\n");
       }
       last_was_empty = false;
       printer->Print("/// $line$\n", "line", *it);
@@ -107,23 +114,23 @@
 }
 
 template <typename DescriptorType>
-void GenerateDocCommentBody(
-  grpc::protobuf::io::Printer* printer, const DescriptorType* descriptor) {
+void GenerateDocCommentBody(grpc::protobuf::io::Printer *printer,
+                            const DescriptorType *descriptor) {
   grpc::protobuf::SourceLocation location;
   if (descriptor->GetSourceLocation(&location)) {
     GenerateDocCommentBodyImpl(printer, location);
   }
 }
 
-std::string GetServiceClassName(const ServiceDescriptor* service) {
+std::string GetServiceClassName(const ServiceDescriptor *service) {
   return service->name();
 }
 
-std::string GetClientClassName(const ServiceDescriptor* service) {
+std::string GetClientClassName(const ServiceDescriptor *service) {
   return service->name() + "Client";
 }
 
-std::string GetServerClassName(const ServiceDescriptor* service) {
+std::string GetServerClassName(const ServiceDescriptor *service) {
   return service->name() + "Base";
 }
 
@@ -138,13 +145,11 @@
     case METHODTYPE_BIDI_STREAMING:
       return "MethodType.DuplexStreaming";
   }
-  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  GOOGLE_LOG(FATAL) << "Can't get here.";
   return "";
 }
 
-std::string GetServiceNameFieldName() {
-  return "__ServiceName";
-}
+std::string GetServiceNameFieldName() { return "__ServiceName"; }
 
 std::string GetMarshallerFieldName(const Descriptor *message) {
   return "__Marshaller_" + message->name();
@@ -155,7 +160,7 @@
 }
 
 std::string GetMethodRequestParamMaybe(const MethodDescriptor *method,
-                                       bool invocation_param=false) {
+                                       bool invocation_param = false) {
   if (method->client_streaming()) {
     return "";
   }
@@ -174,16 +179,16 @@
     case METHODTYPE_NO_STREAMING:
       return "AsyncUnaryCall<" + GetClassName(method->output_type()) + ">";
     case METHODTYPE_CLIENT_STREAMING:
-      return "AsyncClientStreamingCall<" + GetClassName(method->input_type())
-          + ", " + GetClassName(method->output_type()) + ">";
+      return "AsyncClientStreamingCall<" + GetClassName(method->input_type()) +
+             ", " + GetClassName(method->output_type()) + ">";
     case METHODTYPE_SERVER_STREAMING:
-      return "AsyncServerStreamingCall<" + GetClassName(method->output_type())
-          + ">";
+      return "AsyncServerStreamingCall<" + GetClassName(method->output_type()) +
+             ">";
     case METHODTYPE_BIDI_STREAMING:
-      return "AsyncDuplexStreamingCall<" + GetClassName(method->input_type())
-          + ", " + GetClassName(method->output_type()) + ">";
+      return "AsyncDuplexStreamingCall<" + GetClassName(method->input_type()) +
+             ", " + GetClassName(method->output_type()) + ">";
   }
-  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  GOOGLE_LOG(FATAL) << "Can't get here.";
   return "";
 }
 
@@ -194,10 +199,10 @@
       return GetClassName(method->input_type()) + " request";
     case METHODTYPE_CLIENT_STREAMING:
     case METHODTYPE_BIDI_STREAMING:
-      return "IAsyncStreamReader<" + GetClassName(method->input_type())
-          + "> requestStream";
+      return "IAsyncStreamReader<" + GetClassName(method->input_type()) +
+             "> requestStream";
   }
-  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  GOOGLE_LOG(FATAL) << "Can't get here.";
   return "";
 }
 
@@ -205,12 +210,13 @@
   switch (GetMethodType(method)) {
     case METHODTYPE_NO_STREAMING:
     case METHODTYPE_CLIENT_STREAMING:
-      return "global::System.Threading.Tasks.Task<" + GetClassName(method->output_type()) + ">";
+      return "global::System.Threading.Tasks.Task<" +
+             GetClassName(method->output_type()) + ">";
     case METHODTYPE_SERVER_STREAMING:
     case METHODTYPE_BIDI_STREAMING:
       return "global::System.Threading.Tasks.Task";
   }
-  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  GOOGLE_LOG(FATAL) << "Can't get here.";
   return "";
 }
 
@@ -221,18 +227,19 @@
       return "";
     case METHODTYPE_SERVER_STREAMING:
     case METHODTYPE_BIDI_STREAMING:
-      return ", IServerStreamWriter<" + GetClassName(method->output_type())
-          + "> responseStream";
+      return ", IServerStreamWriter<" + GetClassName(method->output_type()) +
+             "> responseStream";
   }
-  GOOGLE_LOG(FATAL)<< "Can't get here.";
+  GOOGLE_LOG(FATAL) << "Can't get here.";
   return "";
 }
 
 // Gets vector of all messages used as input or output types.
-std::vector<const Descriptor*> GetUsedMessages(
+std::vector<const Descriptor *> GetUsedMessages(
     const ServiceDescriptor *service) {
-  std::set<const Descriptor*> descriptor_set;
-  std::vector<const Descriptor*> result;  // vector is to maintain stable ordering
+  std::set<const Descriptor *> descriptor_set;
+  std::vector<const Descriptor *>
+      result;  // vector is to maintain stable ordering
   for (int i = 0; i < service->method_count(); i++) {
     const MethodDescriptor *method = service->method(i);
     if (descriptor_set.find(method->input_type()) == descriptor_set.end()) {
@@ -247,21 +254,25 @@
   return result;
 }
 
-void GenerateMarshallerFields(Printer* out, const ServiceDescriptor *service) {
-  std::vector<const Descriptor*> used_messages = GetUsedMessages(service);
+void GenerateMarshallerFields(Printer *out, const ServiceDescriptor *service) {
+  std::vector<const Descriptor *> used_messages = GetUsedMessages(service);
   for (size_t i = 0; i < used_messages.size(); i++) {
     const Descriptor *message = used_messages[i];
     out->Print(
-        "static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), $type$.Parser.ParseFrom);\n",
+        "static readonly Marshaller<$type$> $fieldname$ = "
+        "Marshallers.Create((arg) => "
+        "global::Google.Protobuf.MessageExtensions.ToByteArray(arg), "
+        "$type$.Parser.ParseFrom);\n",
         "fieldname", GetMarshallerFieldName(message), "type",
         GetClassName(message));
   }
   out->Print("\n");
 }
 
-void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) {
+void GenerateStaticMethodField(Printer *out, const MethodDescriptor *method) {
   out->Print(
-      "static readonly Method<$request$, $response$> $fieldname$ = new Method<$request$, $response$>(\n",
+      "static readonly Method<$request$, $response$> $fieldname$ = new "
+      "Method<$request$, $response$>(\n",
       "fieldname", GetMethodFieldName(method), "request",
       GetClassName(method->input_type()), "response",
       GetClassName(method->output_type()));
@@ -270,7 +281,7 @@
   out->Print("$methodtype$,\n", "methodtype",
              GetCSharpMethodType(GetMethodType(method)));
   out->Print("$servicenamefield$,\n", "servicenamefield",
-               GetServiceNameFieldName());
+             GetServiceNameFieldName());
   out->Print("\"$methodname$\",\n", "methodname", method->name());
   out->Print("$requestmarshaller$,\n", "requestmarshaller",
              GetMarshallerFieldName(method->input_type()));
@@ -281,11 +292,14 @@
   out->Outdent();
 }
 
-void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
+void GenerateServiceDescriptorProperty(Printer *out,
+                                       const ServiceDescriptor *service) {
   std::ostringstream index;
   index << service->index();
   out->Print("/// <summary>Service descriptor</summary>\n");
-  out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
+  out->Print(
+      "public static global::Google.Protobuf.Reflection.ServiceDescriptor "
+      "Descriptor\n");
   out->Print("{\n");
   out->Print("  get { return $umbrella$.Descriptor.Services[$index$]; }\n",
              "umbrella", GetReflectionClassName(service->file()), "index",
@@ -294,9 +308,11 @@
   out->Print("\n");
 }
 
-void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
-  out->Print("/// <summary>Base class for server-side implementations of $servicename$</summary>\n",
-             "servicename", GetServiceClassName(service));
+void GenerateServerClass(Printer *out, const ServiceDescriptor *service) {
+  out->Print(
+      "/// <summary>Base class for server-side implementations of "
+      "$servicename$</summary>\n",
+      "servicename", GetServiceClassName(service));
   out->Print("public abstract class $name$\n", "name",
              GetServerClassName(service));
   out->Print("{\n");
@@ -305,7 +321,8 @@
     const MethodDescriptor *method = service->method(i);
     GenerateDocCommentBody(out, method);
     out->Print(
-        "public virtual $returntype$ $methodname$($request$$response_stream_maybe$, "
+        "public virtual $returntype$ "
+        "$methodname$($request$$response_stream_maybe$, "
         "ServerCallContext context)\n",
         "methodname", method->name(), "returntype",
         GetMethodReturnTypeServer(method), "request",
@@ -313,8 +330,9 @@
         GetMethodResponseStreamMaybe(method));
     out->Print("{\n");
     out->Indent();
-    out->Print("throw new RpcException("
-               "new Status(StatusCode.Unimplemented, \"\"));\n");
+    out->Print(
+        "throw new RpcException("
+        "new Status(StatusCode.Unimplemented, \"\"));\n");
     out->Outdent();
     out->Print("}\n\n");
   }
@@ -323,41 +341,49 @@
   out->Print("\n");
 }
 
-void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
-  out->Print("/// <summary>Client for $servicename$</summary>\n",
-             "servicename", GetServiceClassName(service));
-  out->Print(
-      "public class $name$ : ClientBase<$name$>\n",
-      "name", GetClientClassName(service));
+void GenerateClientStub(Printer *out, const ServiceDescriptor *service) {
+  out->Print("/// <summary>Client for $servicename$</summary>\n", "servicename",
+             GetServiceClassName(service));
+  out->Print("public class $name$ : ClientBase<$name$>\n", "name",
+             GetClientClassName(service));
   out->Print("{\n");
   out->Indent();
 
   // constructors
-  out->Print("/// <summary>Creates a new client for $servicename$</summary>\n"
-             "/// <param name=\"channel\">The channel to use to make remote calls.</param>\n",
-             "servicename", GetServiceClassName(service));
-  out->Print("public $name$(Channel channel) : base(channel)\n",
-             "name", GetClientClassName(service));
+  out->Print(
+      "/// <summary>Creates a new client for $servicename$</summary>\n"
+      "/// <param name=\"channel\">The channel to use to make remote "
+      "calls.</param>\n",
+      "servicename", GetServiceClassName(service));
+  out->Print("public $name$(Channel channel) : base(channel)\n", "name",
+             GetClientClassName(service));
   out->Print("{\n");
   out->Print("}\n");
-  out->Print("/// <summary>Creates a new client for $servicename$ that uses a custom <c>CallInvoker</c>.</summary>\n"
-             "/// <param name=\"callInvoker\">The callInvoker to use to make remote calls.</param>\n",
-             "servicename", GetServiceClassName(service));
+  out->Print(
+      "/// <summary>Creates a new client for $servicename$ that uses a custom "
+      "<c>CallInvoker</c>.</summary>\n"
+      "/// <param name=\"callInvoker\">The callInvoker to use to make remote "
+      "calls.</param>\n",
+      "servicename", GetServiceClassName(service));
   out->Print("public $name$(CallInvoker callInvoker) : base(callInvoker)\n",
              "name", GetClientClassName(service));
   out->Print("{\n");
   out->Print("}\n");
-  out->Print("/// <summary>Protected parameterless constructor to allow creation"
-             " of test doubles.</summary>\n");
-  out->Print("protected $name$() : base()\n",
-             "name", GetClientClassName(service));
+  out->Print(
+      "/// <summary>Protected parameterless constructor to allow creation"
+      " of test doubles.</summary>\n");
+  out->Print("protected $name$() : base()\n", "name",
+             GetClientClassName(service));
   out->Print("{\n");
   out->Print("}\n");
-  out->Print("/// <summary>Protected constructor to allow creation of configured clients.</summary>\n"
-             "/// <param name=\"configuration\">The client configuration.</param>\n");
-  out->Print("protected $name$(ClientBaseConfiguration configuration)"
-             " : base(configuration)\n",
-             "name", GetClientClassName(service));
+  out->Print(
+      "/// <summary>Protected constructor to allow creation of configured "
+      "clients.</summary>\n"
+      "/// <param name=\"configuration\">The client configuration.</param>\n");
+  out->Print(
+      "protected $name$(ClientBaseConfiguration configuration)"
+      " : base(configuration)\n",
+      "name", GetClientClassName(service));
   out->Print("{\n");
   out->Print("}\n\n");
 
@@ -368,27 +394,36 @@
     if (method_type == METHODTYPE_NO_STREAMING) {
       // unary calls have an extra synchronous stub method
       GenerateDocCommentBody(out, method);
-      out->Print("public virtual $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
+      out->Print(
+          "public virtual $response$ $methodname$($request$ request, Metadata "
+          "headers = null, DateTime? deadline = null, CancellationToken "
+          "cancellationToken = default(CancellationToken))\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
           GetClassName(method->output_type()));
       out->Print("{\n");
       out->Indent();
-      out->Print("return $methodname$(request, new CallOptions(headers, deadline, cancellationToken));\n",
-                 "methodname", method->name());
+      out->Print(
+          "return $methodname$(request, new CallOptions(headers, deadline, "
+          "cancellationToken));\n",
+          "methodname", method->name());
       out->Outdent();
       out->Print("}\n");
 
       // overload taking CallOptions as a param
       GenerateDocCommentBody(out, method);
-      out->Print("public virtual $response$ $methodname$($request$ request, CallOptions options)\n",
+      out->Print(
+          "public virtual $response$ $methodname$($request$ request, "
+          "CallOptions options)\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
           GetClassName(method->output_type()));
       out->Print("{\n");
       out->Indent();
-      out->Print("return CallInvoker.BlockingUnaryCall($methodfield$, null, options, request);\n",
-                 "methodfield", GetMethodFieldName(method));
+      out->Print(
+          "return CallInvoker.BlockingUnaryCall($methodfield$, null, options, "
+          "request);\n",
+          "methodfield", GetMethodFieldName(method));
       out->Outdent();
       out->Print("}\n");
     }
@@ -399,23 +434,28 @@
     }
     GenerateDocCommentBody(out, method);
     out->Print(
-            "public virtual $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
-            "methodname", method_name, "request_maybe",
-            GetMethodRequestParamMaybe(method), "returntype",
-            GetMethodReturnTypeClient(method));
+        "public virtual $returntype$ $methodname$($request_maybe$Metadata "
+        "headers = null, DateTime? deadline = null, CancellationToken "
+        "cancellationToken = default(CancellationToken))\n",
+        "methodname", method_name, "request_maybe",
+        GetMethodRequestParamMaybe(method), "returntype",
+        GetMethodReturnTypeClient(method));
     out->Print("{\n");
     out->Indent();
 
-    out->Print("return $methodname$($request_maybe$new CallOptions(headers, deadline, cancellationToken));\n",
-               "methodname", method_name,
-               "request_maybe", GetMethodRequestParamMaybe(method, true));
+    out->Print(
+        "return $methodname$($request_maybe$new CallOptions(headers, deadline, "
+        "cancellationToken));\n",
+        "methodname", method_name, "request_maybe",
+        GetMethodRequestParamMaybe(method, true));
     out->Outdent();
     out->Print("}\n");
 
     // overload taking CallOptions as a param
     GenerateDocCommentBody(out, method);
     out->Print(
-        "public virtual $returntype$ $methodname$($request_maybe$CallOptions options)\n",
+        "public virtual $returntype$ $methodname$($request_maybe$CallOptions "
+        "options)\n",
         "methodname", method_name, "request_maybe",
         GetMethodRequestParamMaybe(method), "returntype",
         GetMethodReturnTypeClient(method));
@@ -423,36 +463,45 @@
     out->Indent();
     switch (GetMethodType(method)) {
       case METHODTYPE_NO_STREAMING:
-        out->Print("return CallInvoker.AsyncUnaryCall($methodfield$, null, options, request);\n",
-                   "methodfield", GetMethodFieldName(method));
+        out->Print(
+            "return CallInvoker.AsyncUnaryCall($methodfield$, null, options, "
+            "request);\n",
+            "methodfield", GetMethodFieldName(method));
         break;
       case METHODTYPE_CLIENT_STREAMING:
-        out->Print("return CallInvoker.AsyncClientStreamingCall($methodfield$, null, options);\n",
-                   "methodfield", GetMethodFieldName(method));
+        out->Print(
+            "return CallInvoker.AsyncClientStreamingCall($methodfield$, null, "
+            "options);\n",
+            "methodfield", GetMethodFieldName(method));
         break;
       case METHODTYPE_SERVER_STREAMING:
         out->Print(
-            "return CallInvoker.AsyncServerStreamingCall($methodfield$, null, options, request);\n",
+            "return CallInvoker.AsyncServerStreamingCall($methodfield$, null, "
+            "options, request);\n",
             "methodfield", GetMethodFieldName(method));
         break;
       case METHODTYPE_BIDI_STREAMING:
-        out->Print("return CallInvoker.AsyncDuplexStreamingCall($methodfield$, null, options);\n",
-                   "methodfield", GetMethodFieldName(method));
+        out->Print(
+            "return CallInvoker.AsyncDuplexStreamingCall($methodfield$, null, "
+            "options);\n",
+            "methodfield", GetMethodFieldName(method));
         break;
       default:
-        GOOGLE_LOG(FATAL)<< "Can't get here.";
+        GOOGLE_LOG(FATAL) << "Can't get here.";
     }
     out->Outdent();
     out->Print("}\n");
   }
 
   // override NewInstance method
-  out->Print("protected override $name$ NewInstance(ClientBaseConfiguration configuration)\n",
-             "name", GetClientClassName(service));
+  out->Print(
+      "protected override $name$ NewInstance(ClientBaseConfiguration "
+      "configuration)\n",
+      "name", GetClientClassName(service));
   out->Print("{\n");
   out->Indent();
-  out->Print("return new $name$(configuration);\n",
-             "name", GetClientClassName(service));
+  out->Print("return new $name$(configuration);\n", "name",
+             GetClientClassName(service));
   out->Outdent();
   out->Print("}\n");
 
@@ -461,11 +510,13 @@
   out->Print("\n");
 }
 
-void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service) {
+void GenerateBindServiceMethod(Printer *out, const ServiceDescriptor *service) {
   out->Print(
-      "/// <summary>Creates service definition that can be registered with a server</summary>\n");
+      "/// <summary>Creates service definition that can be registered with a "
+      "server</summary>\n");
   out->Print(
-      "public static ServerServiceDefinition BindService($implclass$ serviceImpl)\n",
+      "public static ServerServiceDefinition BindService($implclass$ "
+      "serviceImpl)\n",
       "implclass", GetServerClassName(service));
   out->Print("{\n");
   out->Indent();
@@ -491,7 +542,7 @@
   out->Print("\n");
 }
 
-void GenerateService(Printer* out, const ServiceDescriptor *service,
+void GenerateService(Printer *out, const ServiceDescriptor *service,
                      bool generate_client, bool generate_server,
                      bool internal_access) {
   GenerateDocCommentBody(out, service);
diff --git a/src/compiler/csharp_generator_helpers.h b/src/compiler/csharp_generator_helpers.h
index 9bdf6fb..f5d36f2 100644
--- a/src/compiler/csharp_generator_helpers.h
+++ b/src/compiler/csharp_generator_helpers.h
@@ -41,14 +41,16 @@
 
 inline bool ServicesFilename(const grpc::protobuf::FileDescriptor *file,
                              grpc::string *file_name_or_error) {
-  *file_name_or_error = grpc_generator::FileNameInUpperCamel(file, false) + "Grpc.cs";
+  *file_name_or_error =
+      grpc_generator::FileNameInUpperCamel(file, false) + "Grpc.cs";
   return true;
 }
 
 // Get leading or trailing comments in a string. Comment lines start with "// ".
 // Leading detached comments are put in in front of leading comments.
 template <typename DescriptorType>
-inline grpc::string GetCsharpComments(const DescriptorType *desc, bool leading) {
+inline grpc::string GetCsharpComments(const DescriptorType *desc,
+                                      bool leading) {
   return grpc_generator::GetPrefixedComments(desc, leading, "//");
 }
 
diff --git a/src/compiler/csharp_plugin.cc b/src/compiler/csharp_plugin.cc
index 5350e73..7def72c 100644
--- a/src/compiler/csharp_plugin.cc
+++ b/src/compiler/csharp_plugin.cc
@@ -67,10 +67,8 @@
       }
     }
 
-    grpc::string code = grpc_csharp_generator::GetServices(file,
-                                                           generate_client,
-                                                           generate_server,
-                                                           internal_access);
+    grpc::string code = grpc_csharp_generator::GetServices(
+        file, generate_client, generate_server, internal_access);
     if (code.size() == 0) {
       return true;  // don't generate a file if there are no services
     }
diff --git a/src/compiler/generator_helpers.h b/src/compiler/generator_helpers.h
index 9a88c2b..88d96c0 100644
--- a/src/compiler/generator_helpers.h
+++ b/src/compiler/generator_helpers.h
@@ -84,7 +84,7 @@
     }
     str.replace(pos, from.length(), to);
     pos += to.length();
-  } while(replace_all);
+  } while (replace_all);
 
   return str;
 }
@@ -139,8 +139,8 @@
   return result;
 }
 
-inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file,
-                                         bool include_package_path) {
+inline grpc::string FileNameInUpperCamel(
+    const grpc::protobuf::FileDescriptor *file, bool include_package_path) {
   std::vector<grpc::string> tokens = tokenize(StripProto(file->name()), "/");
   grpc::string result = "";
   if (include_package_path) {
@@ -152,7 +152,8 @@
   return result;
 }
 
-inline grpc::string FileNameInUpperCamel(const grpc::protobuf::FileDescriptor *file) {
+inline grpc::string FileNameInUpperCamel(
+    const grpc::protobuf::FileDescriptor *file) {
   return FileNameInUpperCamel(file, true);
 }
 
@@ -163,7 +164,8 @@
   METHODTYPE_BIDI_STREAMING
 };
 
-inline MethodType GetMethodType(const grpc::protobuf::MethodDescriptor *method) {
+inline MethodType GetMethodType(
+    const grpc::protobuf::MethodDescriptor *method) {
   if (method->client_streaming()) {
     if (method->server_streaming()) {
       return METHODTYPE_BIDI_STREAMING;
@@ -254,7 +256,7 @@
     const std::vector<grpc::string> &in, const grpc::string &prefix) {
   std::ostringstream oss;
   for (auto it = in.begin(); it != in.end(); it++) {
-    const grpc::string& elem = *it;
+    const grpc::string &elem = *it;
     if (elem.empty()) {
       oss << prefix << "\n";
     } else if (elem[0] == ' ') {
diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc
index bce156f..d7af125 100644
--- a/src/compiler/node_generator.cc
+++ b/src/compiler/node_generator.cc
@@ -67,15 +67,15 @@
 
 // Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript
 // message file foo/bar/baz.js
-grpc::string GetJSMessageFilename(const grpc::string& filename) {
+grpc::string GetJSMessageFilename(const grpc::string &filename) {
   grpc::string name = filename;
   return grpc_generator::StripProto(name) + "_pb.js";
 }
 
 // Given a filename like foo/bar/baz.proto, returns the root directory
 // path ../../
-grpc::string GetRootPath(const grpc::string& from_filename,
-                         const grpc::string& to_filename) {
+grpc::string GetRootPath(const grpc::string &from_filename,
+                         const grpc::string &to_filename) {
   if (to_filename.find("google/protobuf") == 0) {
     // Well-known types (.proto files in the google/protobuf directory) are
     // assumed to come from the 'google-protobuf' npm package.  We may want to
@@ -96,8 +96,8 @@
 
 // Return the relative path to load to_file from the directory containing
 // from_file, assuming that both paths are relative to the same directory
-grpc::string GetRelativePath(const grpc::string& from_file,
-                             const grpc::string& to_file) {
+grpc::string GetRelativePath(const grpc::string &from_file,
+                             const grpc::string &to_file) {
   return GetRootPath(from_file, to_file) + to_file;
 }
 
@@ -121,7 +121,7 @@
   return message_types;
 }
 
-grpc::string MessageIdentifierName(const grpc::string& name) {
+grpc::string MessageIdentifierName(const grpc::string &name) {
   return grpc_generator::StringReplace(name, ".", "_");
 }
 
@@ -198,18 +198,18 @@
   out->Print(template_vars, "var $name$Service = exports.$name$Service = {\n");
   out->Indent();
   for (int i = 0; i < service->method_count(); i++) {
-    grpc::string method_name = grpc_generator::LowercaseFirstLetter(
-        service->method(i)->name());
+    grpc::string method_name =
+        grpc_generator::LowercaseFirstLetter(service->method(i)->name());
     out->Print(GetNodeComments(service->method(i), true).c_str());
-    out->Print("$method_name$: ",
-               "method_name", method_name);
+    out->Print("$method_name$: ", "method_name", method_name);
     PrintMethod(service->method(i), out);
     out->Print(",\n");
     out->Print(GetNodeComments(service->method(i), false).c_str());
   }
   out->Outdent();
   out->Print("};\n\n");
-  out->Print(template_vars, "exports.$name$Client = "
+  out->Print(template_vars,
+             "exports.$name$Client = "
              "grpc.makeGenericClientConstructor($name$Service);\n");
   out->Print(GetNodeComments(service, false).c_str());
 }
@@ -217,27 +217,25 @@
 void PrintImports(const FileDescriptor *file, Printer *out) {
   out->Print("var grpc = require('grpc');\n");
   if (file->message_type_count() > 0) {
-    grpc::string file_path = GetRelativePath(file->name(),
-                                             GetJSMessageFilename(
-                                                 file->name()));
-    out->Print("var $module_alias$ = require('$file_path$');\n",
-               "module_alias", ModuleAlias(file->name()),
-               "file_path", file_path);
+    grpc::string file_path =
+        GetRelativePath(file->name(), GetJSMessageFilename(file->name()));
+    out->Print("var $module_alias$ = require('$file_path$');\n", "module_alias",
+               ModuleAlias(file->name()), "file_path", file_path);
   }
 
   for (int i = 0; i < file->dependency_count(); i++) {
     grpc::string file_path = GetRelativePath(
         file->name(), GetJSMessageFilename(file->dependency(i)->name()));
-    out->Print("var $module_alias$ = require('$file_path$');\n",
-               "module_alias", ModuleAlias(file->dependency(i)->name()),
-               "file_path", file_path);
+    out->Print("var $module_alias$ = require('$file_path$');\n", "module_alias",
+               ModuleAlias(file->dependency(i)->name()), "file_path",
+               file_path);
   }
   out->Print("\n");
 }
 
 void PrintTransformers(const FileDescriptor *file, Printer *out) {
-  map<grpc::string, const Descriptor*> messages = GetAllMessages(file);
-  for (std::map<grpc::string, const Descriptor*>::iterator it =
+  map<grpc::string, const Descriptor *> messages = GetAllMessages(file);
+  for (std::map<grpc::string, const Descriptor *>::iterator it =
            messages.begin();
        it != messages.end(); it++) {
     PrintMessageTransformer(it->second, out);
@@ -250,7 +248,6 @@
     PrintService(file->service(i), out);
   }
 }
-
 }
 
 grpc::string GenerateFile(const FileDescriptor *file) {
diff --git a/src/compiler/node_generator_helpers.h b/src/compiler/node_generator_helpers.h
index 5862772..efe94ab 100644
--- a/src/compiler/node_generator_helpers.h
+++ b/src/compiler/node_generator_helpers.h
@@ -48,7 +48,7 @@
 // Get leading or trailing comments in a string. Comment lines start with "// ".
 // Leading detached comments are put in in front of leading comments.
 template <typename DescriptorType>
-inline grpc::string GetNodeComments(const DescriptorType *desc, bool leading) {
+inline grpc::string GetNodeComments(const DescriptorType* desc, bool leading) {
   return grpc_generator::GetPrefixedComments(desc, leading, "//");
 }
 
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index 4be8cb4..1d7faf1 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -49,9 +49,9 @@
 namespace grpc_objective_c_generator {
 namespace {
 
-void PrintProtoRpcDeclarationAsPragma(Printer *printer,
-                                      const MethodDescriptor *method,
-                                      map< ::grpc::string, ::grpc::string> vars) {
+void PrintProtoRpcDeclarationAsPragma(
+    Printer *printer, const MethodDescriptor *method,
+    map< ::grpc::string, ::grpc::string> vars) {
   vars["client_stream"] = method->client_streaming() ? "stream " : "";
   vars["server_stream"] = method->server_streaming() ? "stream " : "";
 
@@ -61,7 +61,7 @@
 }
 
 template <typename DescriptorType>
-static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
+static void PrintAllComments(const DescriptorType *desc, Printer *printer) {
   std::vector<grpc::string> comments;
   grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
                              &comments);
@@ -100,7 +100,8 @@
   if (method->server_streaming()) {
     printer->Print(vars,
                    " eventHandler:(void(^)(BOOL done, "
-                   "$response_class$ *_Nullable response, NSError *_Nullable error))eventHandler");
+                   "$response_class$ *_Nullable response, NSError *_Nullable "
+                   "error))eventHandler");
   } else {
     printer->Print(vars,
                    " handler:(void(^)($response_class$ *_Nullable response, "
@@ -123,7 +124,8 @@
   PrintMethodSignature(printer, method, vars);
 }
 
-inline map< ::grpc::string, ::grpc::string> GetMethodVars(const MethodDescriptor *method) {
+inline map< ::grpc::string, ::grpc::string> GetMethodVars(
+    const MethodDescriptor *method) {
   map< ::grpc::string, ::grpc::string> res;
   res["method_name"] = method->name();
   res["request_type"] = method->input_type()->name();
@@ -210,7 +212,8 @@
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     Printer printer(&output_stream, '$');
 
-    map< ::grpc::string, ::grpc::string> vars = {{"service_class", ServiceClassName(service)}};
+    map< ::grpc::string, ::grpc::string> vars = {
+        {"service_class", ServiceClassName(service)}};
 
     printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
 
@@ -237,21 +240,23 @@
 }
 
 ::grpc::string GetSource(const ServiceDescriptor *service) {
- ::grpc::string output;
+  ::grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     Printer printer(&output_stream, '$');
 
-    map< ::grpc::string,::grpc::string> vars = {{"service_name", service->name()},
-                                {"service_class", ServiceClassName(service)},
-                                {"package", service->file()->package()}};
+    map< ::grpc::string, ::grpc::string> vars = {
+        {"service_name", service->name()},
+        {"service_class", ServiceClassName(service)},
+        {"package", service->file()->package()}};
 
     printer.Print(vars, "@implementation $service_class$\n\n");
 
     printer.Print("// Designated initializer\n");
     printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
-    printer.Print(vars,
+    printer.Print(
+        vars,
         "  return (self = [super initWithHost:host"
         " packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
     printer.Print("}\n\n");
diff --git a/src/compiler/objective_c_generator_helpers.h b/src/compiler/objective_c_generator_helpers.h
index 1f8c800..b482f02 100644
--- a/src/compiler/objective_c_generator_helpers.h
+++ b/src/compiler/objective_c_generator_helpers.h
@@ -53,6 +53,5 @@
   string prefix = file->options().objc_class_prefix();
   return prefix + service->name();
 }
-
 }
 #endif  // GRPC_INTERNAL_COMPILER_OBJECTIVE_C_GENERATOR_HELPERS_H
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index be64776..8de0997 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -42,7 +42,8 @@
 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
 
 using ::google::protobuf::compiler::objectivec::ProtobufLibraryFrameworkName;
-using ::google::protobuf::compiler::objectivec::IsProtobufLibraryBundledProtoFile;
+using ::google::protobuf::compiler::objectivec::
+    IsProtobufLibraryBundledProtoFile;
 
 class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
  public:
@@ -53,7 +54,6 @@
                         const ::grpc::string &parameter,
                         grpc::protobuf::compiler::GeneratorContext *context,
                         ::grpc::string *error) const {
-
     if (file->service_count() == 0) {
       // No services.  Do nothing.
       return true;
@@ -66,29 +66,32 @@
       // Generate .pbrpc.h
 
       ::grpc::string imports = ::grpc::string("#import \"") + file_name +
-        ".pbobjc.h\"\n\n"
-        "#import <ProtoRPC/ProtoService.h>\n"
-        "#import <RxLibrary/GRXWriteable.h>\n"
-        "#import <RxLibrary/GRXWriter.h>\n";
+                               ".pbobjc.h\"\n\n"
+                               "#import <ProtoRPC/ProtoService.h>\n"
+                               "#import <RxLibrary/GRXWriteable.h>\n"
+                               "#import <RxLibrary/GRXWriter.h>\n";
 
       // TODO(jcanizales): Instead forward-declare the input and output types
       // and import the files in the .pbrpc.m
       ::grpc::string proto_imports;
       for (int i = 0; i < file->dependency_count(); i++) {
-        ::grpc::string header = grpc_objective_c_generator::MessageHeaderName(
-            file->dependency(i));
+        ::grpc::string header =
+            grpc_objective_c_generator::MessageHeaderName(file->dependency(i));
         const grpc::protobuf::FileDescriptor *dependency = file->dependency(i);
         if (IsProtobufLibraryBundledProtoFile(dependency)) {
           ::grpc::string base_name = header;
           grpc_generator::StripPrefix(&base_name, "google/protobuf/");
           // create the import code snippet
           proto_imports +=
-            "#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
-            "  #import <" + ::grpc::string(ProtobufLibraryFrameworkName) +
-            "/" + base_name + ">\n"
-            "#else\n"
-            "  #import \"" + header + "\"\n"
-            "#endif\n";
+              "#if GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS\n"
+              "  #import <" +
+              ::grpc::string(ProtobufLibraryFrameworkName) + "/" + base_name +
+              ">\n"
+              "#else\n"
+              "  #import \"" +
+              header +
+              "\"\n"
+              "#endif\n";
         } else {
           proto_imports += ::grpc::string("#import \"") + header + "\"\n";
         }
@@ -100,21 +103,22 @@
         declarations += grpc_objective_c_generator::GetHeader(service);
       }
 
-      static const ::grpc::string kNonNullBegin = "\nNS_ASSUME_NONNULL_BEGIN\n\n";
+      static const ::grpc::string kNonNullBegin =
+          "\nNS_ASSUME_NONNULL_BEGIN\n\n";
       static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
 
-      Write(context, file_name + ".pbrpc.h",
-          imports + '\n' + proto_imports + '\n' + kNonNullBegin +
-          declarations + kNonNullEnd);
+      Write(context, file_name + ".pbrpc.h", imports + '\n' + proto_imports +
+                                                 '\n' + kNonNullBegin +
+                                                 declarations + kNonNullEnd);
     }
 
     {
       // Generate .pbrpc.m
 
       ::grpc::string imports = ::grpc::string("#import \"") + file_name +
-        ".pbrpc.h\"\n\n"
-        "#import <ProtoRPC/ProtoRPC.h>\n"
-        "#import <RxLibrary/GRXWriter+Immediate.h>\n";
+                               ".pbrpc.h\"\n\n"
+                               "#import <ProtoRPC/ProtoRPC.h>\n"
+                               "#import <RxLibrary/GRXWriter+Immediate.h>\n";
 
       ::grpc::string definitions;
       for (int i = 0; i < file->service_count(); i++) {
@@ -131,7 +135,7 @@
  private:
   // Write the given code into the given file.
   void Write(grpc::protobuf::compiler::GeneratorContext *context,
-              const ::grpc::string &filename, const ::grpc::string &code) const {
+             const ::grpc::string &filename, const ::grpc::string &code) const {
     std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
         context->Open(filename));
     grpc::protobuf::io::CodedOutputStream coded_out(output.get());
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index c5f1ed8..0f61b1f 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -74,16 +74,18 @@
 
 PythonGrpcGenerator::~PythonGrpcGenerator() {}
 
-bool PythonGrpcGenerator::Generate(
-    const FileDescriptor* file, const grpc::string& parameter,
-    GeneratorContext* context, grpc::string* error) const {
+bool PythonGrpcGenerator::Generate(const FileDescriptor* file,
+                                   const grpc::string& parameter,
+                                   GeneratorContext* context,
+                                   grpc::string* error) const {
   // Get output file name.
   grpc::string file_name;
   static const int proto_suffix_length = strlen(".proto");
   if (file->name().size() > static_cast<size_t>(proto_suffix_length) &&
       file->name().find_last_of(".proto") == file->name().size() - 1) {
-    file_name = file->name().substr(
-        0, file->name().size() - proto_suffix_length) + "_pb2.py";
+    file_name =
+        file->name().substr(0, file->name().size() - proto_suffix_length) +
+        "_pb2.py";
   } else {
     *error = "Invalid proto file name. Proto file must end with .proto";
     return false;
@@ -115,7 +117,7 @@
   assert(values.size() % 2 == 0);
   map<grpc::string, grpc::string> value_map;
   auto value_iter = values.begin();
-  for (unsigned i = 0; i < values.size()/2; ++i) {
+  for (unsigned i = 0; i < values.size() / 2; ++i) {
     grpc::string key = *value_iter;
     ++value_iter;
     grpc::string value = *value_iter;
@@ -138,9 +140,7 @@
     printer_->Indent();
   }
 
-  ~IndentScope() {
-    printer_->Outdent();
-  }
+  ~IndentScope() { printer_->Outdent(); }
 
  private:
   Printer* printer_;
@@ -173,7 +173,6 @@
   return module_name;
 }
 
-
 bool GetModuleAndMessagePath(const Descriptor* type,
                              const ServiceDescriptor* service,
                              grpc::string* out) {
@@ -182,7 +181,7 @@
   do {
     message_path.push_back(path_elem_type);
     path_elem_type = path_elem_type->containing_type();
-  } while (path_elem_type); // implicit nullptr comparison; don't be explicit
+  } while (path_elem_type);  // implicit nullptr comparison; don't be explicit
   grpc::string file_name = type->file()->name();
   static const int proto_suffix_length = strlen(".proto");
   if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
@@ -190,11 +189,11 @@
     return false;
   }
   grpc::string service_file_name = service->file()->name();
-  grpc::string module = service_file_name == file_name ?
-          "" : ModuleAlias(file_name) + ".";
+  grpc::string module =
+      service_file_name == file_name ? "" : ModuleAlias(file_name) + ".";
   grpc::string message_type;
-  for (auto path_iter = message_path.rbegin();
-       path_iter != message_path.rend(); ++path_iter) {
+  for (auto path_iter = message_path.rbegin(); path_iter != message_path.rend();
+       ++path_iter) {
     message_type += (*path_iter)->name() + ".";
   }
   // no pop_back prior to C++11
@@ -229,8 +228,7 @@
   printer->Print("\"\"\"\n");
 }
 
-bool PrintBetaServicer(const ServiceDescriptor* service,
-                       Printer* out) {
+bool PrintBetaServicer(const ServiceDescriptor* service, Printer* out) {
   out->Print("\n\n");
   out->Print("class Beta$Service$Servicer(object):\n", "Service",
              service->name());
@@ -239,10 +237,10 @@
     PrintAllComments(service, out);
     for (int i = 0; i < service->method_count(); ++i) {
       auto meth = service->method(i);
-      grpc::string arg_name = meth->client_streaming() ?
-          "request_iterator" : "request";
-      out->Print("def $Method$(self, $ArgName$, context):\n",
-                 "Method", meth->name(), "ArgName", arg_name);
+      grpc::string arg_name =
+          meth->client_streaming() ? "request_iterator" : "request";
+      out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
+                 meth->name(), "ArgName", arg_name);
       {
         IndentScope raii_method_indent(out);
         PrintAllComments(meth, out);
@@ -253,8 +251,7 @@
   return true;
 }
 
-bool PrintBetaStub(const ServiceDescriptor* service,
-                   Printer* out) {
+bool PrintBetaStub(const ServiceDescriptor* service, Printer* out) {
   out->Print("\n\n");
   out->Print("class Beta$Service$Stub(object):\n", "Service", service->name());
   {
@@ -262,10 +259,12 @@
     PrintAllComments(service, out);
     for (int i = 0; i < service->method_count(); ++i) {
       const MethodDescriptor* meth = service->method(i);
-      grpc::string arg_name = meth->client_streaming() ?
-          "request_iterator" : "request";
+      grpc::string arg_name =
+          meth->client_streaming() ? "request_iterator" : "request";
       auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
-      out->Print(methdict, "def $Method$(self, $ArgName$, timeout, metadata=None, with_call=False, protocol_options=None):\n");
+      out->Print(methdict,
+                 "def $Method$(self, $ArgName$, timeout, metadata=None, "
+                 "with_call=False, protocol_options=None):\n");
       {
         IndentScope raii_method_indent(out);
         PrintAllComments(meth, out);
@@ -282,9 +281,10 @@
 bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name,
                             const ServiceDescriptor* service, Printer* out) {
   out->Print("\n\n");
-  out->Print("def beta_create_$Service$_server(servicer, pool=None, "
-             "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
-             "Service", service->name());
+  out->Print(
+      "def beta_create_$Service$_server(servicer, pool=None, "
+      "pool_size=None, default_timeout=None, maximum_timeout=None):\n",
+      "Service", service->name());
   {
     IndentScope raii_create_server_indent(out);
     map<grpc::string, grpc::string> method_implementation_constructors;
@@ -315,58 +315,62 @@
     }
     out->Print("request_deserializers = {\n");
     for (auto name_and_input_module_class_pair =
-           input_message_modules_and_classes.begin();
+             input_message_modules_and_classes.begin();
          name_and_input_module_class_pair !=
-           input_message_modules_and_classes.end();
+         input_message_modules_and_classes.end();
          name_and_input_module_class_pair++) {
       IndentScope raii_indent(out);
-      out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-                 "$InputTypeModuleAndClass$.FromString,\n",
-                 "PackageQualifiedServiceName", package_qualified_service_name,
-                 "MethodName", name_and_input_module_class_pair->first,
-                 "InputTypeModuleAndClass",
-                 name_and_input_module_class_pair->second);
+      out->Print(
+          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+          "$InputTypeModuleAndClass$.FromString,\n",
+          "PackageQualifiedServiceName", package_qualified_service_name,
+          "MethodName", name_and_input_module_class_pair->first,
+          "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
     }
     out->Print("}\n");
     out->Print("response_serializers = {\n");
     for (auto name_and_output_module_class_pair =
-           output_message_modules_and_classes.begin();
+             output_message_modules_and_classes.begin();
          name_and_output_module_class_pair !=
-           output_message_modules_and_classes.end();
+         output_message_modules_and_classes.end();
          name_and_output_module_class_pair++) {
       IndentScope raii_indent(out);
-      out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-                 "$OutputTypeModuleAndClass$.SerializeToString,\n",
-                 "PackageQualifiedServiceName", package_qualified_service_name,
-                 "MethodName", name_and_output_module_class_pair->first,
-                 "OutputTypeModuleAndClass",
-                 name_and_output_module_class_pair->second);
+      out->Print(
+          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+          "$OutputTypeModuleAndClass$.SerializeToString,\n",
+          "PackageQualifiedServiceName", package_qualified_service_name,
+          "MethodName", name_and_output_module_class_pair->first,
+          "OutputTypeModuleAndClass",
+          name_and_output_module_class_pair->second);
     }
     out->Print("}\n");
     out->Print("method_implementations = {\n");
     for (auto name_and_implementation_constructor =
-           method_implementation_constructors.begin();
-	 name_and_implementation_constructor !=
-	   method_implementation_constructors.end();
-	 name_and_implementation_constructor++) {
+             method_implementation_constructors.begin();
+         name_and_implementation_constructor !=
+         method_implementation_constructors.end();
+         name_and_implementation_constructor++) {
       IndentScope raii_descriptions_indent(out);
       const grpc::string method_name =
           name_and_implementation_constructor->first;
-      out->Print("(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
-                 "face_utilities.$Constructor$(servicer.$Method$),\n",
-                 "PackageQualifiedServiceName", package_qualified_service_name,
-                 "Method", name_and_implementation_constructor->first,
-                 "Constructor", name_and_implementation_constructor->second);
+      out->Print(
+          "(\'$PackageQualifiedServiceName$\', \'$Method$\'): "
+          "face_utilities.$Constructor$(servicer.$Method$),\n",
+          "PackageQualifiedServiceName", package_qualified_service_name,
+          "Method", name_and_implementation_constructor->first, "Constructor",
+          name_and_implementation_constructor->second);
     }
     out->Print("}\n");
-    out->Print("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)\n");
-    out->Print("return beta_implementations.server(method_implementations, "
-               "options=server_options)\n");
+    out->Print(
+        "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)\n");
+    out->Print(
+        "return beta_implementations.server(method_implementations, "
+        "options=server_options)\n");
   }
   return true;
 }
@@ -374,10 +378,11 @@
 bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name,
                           const ServiceDescriptor* service, Printer* out) {
   map<grpc::string, grpc::string> dict = ListToDict({
-        "Service", service->name(),
-      });
+      "Service", service->name(),
+  });
   out->Print("\n\n");
-  out->Print(dict, "def beta_create_$Service$_stub(channel, host=None,"
+  out->Print(dict,
+             "def beta_create_$Service$_stub(channel, host=None,"
              " metadata_transformer=None, pool=None, pool_size=None):\n");
   {
     IndentScope raii_create_server_indent(out);
@@ -387,8 +392,7 @@
     for (int i = 0; i < service->method_count(); ++i) {
       const MethodDescriptor* method = service->method(i);
       const grpc::string method_cardinality =
-          grpc::string(method->client_streaming() ? "STREAM" : "UNARY") +
-          "_" +
+          grpc::string(method->client_streaming() ? "STREAM" : "UNARY") + "_" +
           grpc::string(method->server_streaming() ? "STREAM" : "UNARY");
       grpc::string input_message_module_and_class;
       if (!GetModuleAndMessagePath(method->input_type(), service,
@@ -409,32 +413,33 @@
     }
     out->Print("request_serializers = {\n");
     for (auto name_and_input_module_class_pair =
-           input_message_modules_and_classes.begin();
+             input_message_modules_and_classes.begin();
          name_and_input_module_class_pair !=
-           input_message_modules_and_classes.end();
+         input_message_modules_and_classes.end();
          name_and_input_module_class_pair++) {
       IndentScope raii_indent(out);
-      out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-                 "$InputTypeModuleAndClass$.SerializeToString,\n",
-                 "PackageQualifiedServiceName", package_qualified_service_name,
-                 "MethodName", name_and_input_module_class_pair->first,
-                 "InputTypeModuleAndClass",
-                 name_and_input_module_class_pair->second);
+      out->Print(
+          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+          "$InputTypeModuleAndClass$.SerializeToString,\n",
+          "PackageQualifiedServiceName", package_qualified_service_name,
+          "MethodName", name_and_input_module_class_pair->first,
+          "InputTypeModuleAndClass", name_and_input_module_class_pair->second);
     }
     out->Print("}\n");
     out->Print("response_deserializers = {\n");
     for (auto name_and_output_module_class_pair =
-           output_message_modules_and_classes.begin();
+             output_message_modules_and_classes.begin();
          name_and_output_module_class_pair !=
-           output_message_modules_and_classes.end();
+         output_message_modules_and_classes.end();
          name_and_output_module_class_pair++) {
       IndentScope raii_indent(out);
-      out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
-                 "$OutputTypeModuleAndClass$.FromString,\n",
-                 "PackageQualifiedServiceName", package_qualified_service_name,
-                 "MethodName", name_and_output_module_class_pair->first,
-                 "OutputTypeModuleAndClass",
-                 name_and_output_module_class_pair->second);
+      out->Print(
+          "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): "
+          "$OutputTypeModuleAndClass$.FromString,\n",
+          "PackageQualifiedServiceName", package_qualified_service_name,
+          "MethodName", name_and_output_module_class_pair->first,
+          "OutputTypeModuleAndClass",
+          name_and_output_module_class_pair->second);
     }
     out->Print("}\n");
     out->Print("cardinalities = {\n");
@@ -443,17 +448,19 @@
          name_and_cardinality++) {
       IndentScope raii_descriptions_indent(out);
       out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n",
-                 "Method", name_and_cardinality->first,
-                 "Cardinality", name_and_cardinality->second);
+                 "Method", name_and_cardinality->first, "Cardinality",
+                 name_and_cardinality->second);
     }
     out->Print("}\n");
-    out->Print("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)\n");
     out->Print(
-        "return beta_implementations.dynamic_stub(channel, \'$PackageQualifiedServiceName$\', "
+        "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)\n");
+    out->Print(
+        "return beta_implementations.dynamic_stub(channel, "
+        "\'$PackageQualifiedServiceName$\', "
         "cardinalities, options=stub_options)\n",
         "PackageQualifiedServiceName", package_qualified_service_name);
   }
@@ -476,43 +483,41 @@
       out->Print("Args:\n");
       {
         IndentScope raii_args_indent(out);
-	out->Print("channel: A grpc.Channel.\n");
+        out->Print("channel: A grpc.Channel.\n");
       }
       out->Print("\"\"\"\n");
       for (int i = 0; i < service->method_count(); ++i) {
         auto method = service->method(i);
-	auto multi_callable_constructor =
-	    grpc::string(method->client_streaming() ? "stream" : "unary") +
-	    "_" +
-	    grpc::string(method->server_streaming() ? "stream" : "unary");
-	grpc::string request_module_and_class;
-	if (!GetModuleAndMessagePath(method->input_type(), service,
-				     &request_module_and_class)) {
-	  return false;
-	}
-	grpc::string response_module_and_class;
-	if (!GetModuleAndMessagePath(method->output_type(), service,
-				     &response_module_and_class)) {
+        auto multi_callable_constructor =
+            grpc::string(method->client_streaming() ? "stream" : "unary") +
+            "_" + grpc::string(method->server_streaming() ? "stream" : "unary");
+        grpc::string request_module_and_class;
+        if (!GetModuleAndMessagePath(method->input_type(), service,
+                                     &request_module_and_class)) {
           return false;
-	}
-	out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
-		   "Method", method->name(),
-		   "MultiCallableConstructor", multi_callable_constructor);
-	{
+        }
+        grpc::string response_module_and_class;
+        if (!GetModuleAndMessagePath(method->output_type(), service,
+                                     &response_module_and_class)) {
+          return false;
+        }
+        out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n",
+                   "Method", method->name(), "MultiCallableConstructor",
+                   multi_callable_constructor);
+        {
           IndentScope raii_first_attribute_indent(out);
           IndentScope raii_second_attribute_indent(out);
-	  out->Print(
-	      "'/$PackageQualifiedService$/$Method$',\n",
-	      "PackageQualifiedService", package_qualified_service_name,
-	      "Method", method->name());
-	  out->Print(
-	      "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
-	      "RequestModuleAndClass", request_module_and_class);
-	  out->Print(
+          out->Print("'/$PackageQualifiedService$/$Method$',\n",
+                     "PackageQualifiedService", package_qualified_service_name,
+                     "Method", method->name());
+          out->Print(
+              "request_serializer=$RequestModuleAndClass$.SerializeToString,\n",
+              "RequestModuleAndClass", request_module_and_class);
+          out->Print(
               "response_deserializer=$ResponseModuleAndClass$.FromString,\n",
-	      "ResponseModuleAndClass", response_module_and_class);
-	  out->Print(")\n");
-	}
+              "ResponseModuleAndClass", response_module_and_class);
+          out->Print(")\n");
+        }
       }
     }
   }
@@ -527,11 +532,11 @@
     PrintAllComments(service, out);
     for (int i = 0; i < service->method_count(); ++i) {
       auto method = service->method(i);
-      grpc::string arg_name = method->client_streaming() ?
-	  "request_iterator" : "request";
+      grpc::string arg_name =
+          method->client_streaming() ? "request_iterator" : "request";
       out->Print("\n");
-      out->Print("def $Method$(self, $ArgName$, context):\n",
-                 "Method", method->name(), "ArgName", arg_name);
+      out->Print("def $Method$(self, $ArgName$, context):\n", "Method",
+                 method->name(), "ArgName", arg_name);
       {
         IndentScope raii_method_indent(out);
         PrintAllComments(method, out);
@@ -544,11 +549,12 @@
   return true;
 }
 
-bool PrintAddServicerToServer(const grpc::string& package_qualified_service_name,
-			      const ServiceDescriptor* service, Printer* out) {
+bool PrintAddServicerToServer(
+    const grpc::string& package_qualified_service_name,
+    const ServiceDescriptor* service, Printer* out) {
   out->Print("\n\n");
   out->Print("def add_$Service$Servicer_to_server(servicer, server):\n",
-	     "Service", service->name());
+             "Service", service->name());
   {
     IndentScope raii_class_indent(out);
     out->Print("rpc_method_handlers = {\n");
@@ -557,34 +563,37 @@
       IndentScope raii_dict_second_indent(out);
       for (int i = 0; i < service->method_count(); ++i) {
         auto method = service->method(i);
-	auto method_handler_constructor =
+        auto method_handler_constructor =
             grpc::string(method->client_streaming() ? "stream" : "unary") +
-	    "_" +
+            "_" +
             grpc::string(method->server_streaming() ? "stream" : "unary") +
             "_rpc_method_handler";
-	grpc::string request_module_and_class;
-	if (!GetModuleAndMessagePath(method->input_type(), service,
-				     &request_module_and_class)) {
-	  return false;
-	}
-	grpc::string response_module_and_class;
-	if (!GetModuleAndMessagePath(method->output_type(), service,
-				     &response_module_and_class)) {
+        grpc::string request_module_and_class;
+        if (!GetModuleAndMessagePath(method->input_type(), service,
+                                     &request_module_and_class)) {
           return false;
-	}
-        out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n",
-		   "Method", method->name(),
-		   "MethodHandlerConstructor", method_handler_constructor);
-	{
+        }
+        grpc::string response_module_and_class;
+        if (!GetModuleAndMessagePath(method->output_type(), service,
+                                     &response_module_and_class)) {
+          return false;
+        }
+        out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n", "Method",
+                   method->name(), "MethodHandlerConstructor",
+                   method_handler_constructor);
+        {
           IndentScope raii_call_first_indent(out);
-	  IndentScope raii_call_second_indent(out);
-	  out->Print("servicer.$Method$,\n", "Method", method->name());
-	  out->Print("request_deserializer=$RequestModuleAndClass$.FromString,\n",
-		     "RequestModuleAndClass", request_module_and_class);
-	  out->Print("response_serializer=$ResponseModuleAndClass$.SerializeToString,\n",
-		     "ResponseModuleAndClass", response_module_and_class);
-	}
-	out->Print("),\n");
+          IndentScope raii_call_second_indent(out);
+          out->Print("servicer.$Method$,\n", "Method", method->name());
+          out->Print(
+              "request_deserializer=$RequestModuleAndClass$.FromString,\n",
+              "RequestModuleAndClass", request_module_and_class);
+          out->Print(
+              "response_serializer=$ResponseModuleAndClass$.SerializeToString,"
+              "\n",
+              "ResponseModuleAndClass", response_module_and_class);
+        }
+        out->Print("),\n");
       }
     }
     out->Print("}\n");
@@ -593,7 +602,7 @@
       IndentScope raii_call_first_indent(out);
       IndentScope raii_call_second_indent(out);
       out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n",
-		 "PackageQualifiedServiceName", package_qualified_service_name);
+                 "PackageQualifiedServiceName", package_qualified_service_name);
     }
     out->Print("server.add_generic_rpc_handlers((generic_handler,))\n");
   }
@@ -605,10 +614,12 @@
   out->Print("import $Package$\n", "Package", config.grpc_package_root);
   out->Print("from $Package$ import implementations as beta_implementations\n",
              "Package", config.beta_package_root);
-  out->Print("from $Package$ import interfaces as beta_interfaces\n",
-             "Package", config.beta_package_root);
+  out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package",
+             config.beta_package_root);
   out->Print("from grpc.framework.common import cardinality\n");
-  out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
+  out->Print(
+      "from grpc.framework.interfaces.face import utilities as "
+      "face_utilities\n");
   return true;
 }
 
@@ -632,12 +643,14 @@
       auto service = file->service(i);
       auto package_qualified_service_name = package + service->name();
       if (!(PrintStub(package_qualified_service_name, service, &out) &&
-	    PrintServicer(service, &out) &&
-	    PrintAddServicerToServer(package_qualified_service_name, service, &out) &&
-	    PrintBetaServicer(service, &out) &&
-            PrintBetaStub(service, &out) &&
-            PrintBetaServerFactory(package_qualified_service_name, service, &out) &&
-            PrintBetaStubFactory(package_qualified_service_name, service, &out))) {
+            PrintServicer(service, &out) &&
+            PrintAddServicerToServer(package_qualified_service_name, service,
+                                     &out) &&
+            PrintBetaServicer(service, &out) && PrintBetaStub(service, &out) &&
+            PrintBetaServerFactory(package_qualified_service_name, service,
+                                   &out) &&
+            PrintBetaStubFactory(package_qualified_service_name, service,
+                                 &out))) {
         return make_pair(false, "");
       }
     }
diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h
index 7ed99ef..9bbb83b 100644
--- a/src/compiler/python_generator.h
+++ b/src/compiler/python_generator.h
@@ -57,6 +57,7 @@
                 const grpc::string& parameter,
                 grpc::protobuf::compiler::GeneratorContext* context,
                 grpc::string* error) const;
+
  private:
   GeneratorConfiguration config_;
 };
diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index 1501c3f..0220256 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -55,17 +55,20 @@
 // Prints out the method using the ruby gRPC DSL.
 void PrintMethod(const MethodDescriptor *method, const grpc::string &package,
                  Printer *out) {
-  grpc::string input_type = RubyTypeOf(method->input_type()->full_name(), package);
+  grpc::string input_type =
+      RubyTypeOf(method->input_type()->full_name(), package);
   if (method->client_streaming()) {
     input_type = "stream(" + input_type + ")";
   }
-  grpc::string output_type = RubyTypeOf(method->output_type()->full_name(), package);
+  grpc::string output_type =
+      RubyTypeOf(method->output_type()->full_name(), package);
   if (method->server_streaming()) {
     output_type = "stream(" + output_type + ")";
   }
-  std::map<grpc::string, grpc::string> method_vars =
-      ListToDict({"mth.name", method->name(), "input.type", input_type,
-                  "output.type", output_type, });
+  std::map<grpc::string, grpc::string> method_vars = ListToDict({
+      "mth.name", method->name(), "input.type", input_type, "output.type",
+      output_type,
+  });
   out->Print(GetRubyComments(method, true).c_str());
   out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n");
   out->Print(GetRubyComments(method, false).c_str());
@@ -79,8 +82,9 @@
   }
 
   // Begin the service module
-  std::map<grpc::string, grpc::string> module_vars =
-      ListToDict({"module.name", CapitalizeFirst(service->name()), });
+  std::map<grpc::string, grpc::string> module_vars = ListToDict({
+      "module.name", CapitalizeFirst(service->name()),
+  });
   out->Print(module_vars, "module $module.name$\n");
   out->Indent();
 
@@ -130,8 +134,9 @@
     }
 
     // Write out a file header.
-    std::map<grpc::string, grpc::string> header_comment_vars = ListToDict(
-        {"file.name", file->name(), "file.package", file->package(), });
+    std::map<grpc::string, grpc::string> header_comment_vars = ListToDict({
+        "file.name", file->name(), "file.package", file->package(),
+    });
     out.Print("# Generated by the protocol buffer compiler.  DO NOT EDIT!\n");
     out.Print(header_comment_vars,
               "# Source: $file.name$ for package '$file.package$'\n");
@@ -147,16 +152,18 @@
     // Write out require statemment to import the separately generated file
     // that defines the messages used by the service. This is generated by the
     // main ruby plugin.
-    std::map<grpc::string, grpc::string> dep_vars =
-        ListToDict({"dep.name", MessagesRequireName(file), });
+    std::map<grpc::string, grpc::string> dep_vars = ListToDict({
+        "dep.name", MessagesRequireName(file),
+    });
     out.Print(dep_vars, "require '$dep.name$'\n");
 
     // Write out services within the modules
     out.Print("\n");
     std::vector<grpc::string> modules = Split(file->package(), '.');
     for (size_t i = 0; i < modules.size(); ++i) {
-      std::map<grpc::string, grpc::string> module_vars =
-          ListToDict({"module.name", CapitalizeFirst(modules[i]), });
+      std::map<grpc::string, grpc::string> module_vars = ListToDict({
+          "module.name", CapitalizeFirst(modules[i]),
+      });
       out.Print(module_vars, "module $module.name$\n");
       out.Indent();
     }
diff --git a/src/compiler/ruby_generator_map-inl.h b/src/compiler/ruby_generator_map-inl.h
index 6b87774..75ba7fc 100644
--- a/src/compiler/ruby_generator_map-inl.h
+++ b/src/compiler/ruby_generator_map-inl.h
@@ -36,8 +36,8 @@
 
 #include "src/compiler/config.h"
 
-#include <iostream>
 #include <initializer_list>
+#include <iostream>
 #include <map>
 #include <ostream>  // NOLINT
 #include <vector>
@@ -53,8 +53,7 @@
 inline std::map<grpc::string, grpc::string> ListToDict(
     const initializer_list<grpc::string> &values) {
   if (values.size() % 2 != 0) {
-    std::cerr << "Not every 'key' has a value in `values`."
-              << std::endl;
+    std::cerr << "Not every 'key' has a value in `values`." << std::endl;
   }
   std::map<grpc::string, grpc::string> value_map;
   auto value_iter = values.begin();
diff --git a/src/core/ext/census/base_resources.c b/src/core/ext/census/base_resources.c
new file mode 100644
index 0000000..f9aa4bb
--- /dev/null
+++ b/src/core/ext/census/base_resources.c
@@ -0,0 +1,71 @@
+/*
+ * 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/ext/census/base_resources.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/census.h>
+#include <grpc/support/log.h>
+
+#include "src/core/ext/census/resource.h"
+
+// Add base RPC resource definitions for use by RPC runtime.
+//
+// TODO(aveitch): All of these are currently hardwired definitions encoded in
+// the code in this file. These should be converted to use an external
+// configuration mechanism, in which these resources are defined in a text
+// file, which is compiled to .pb format and read by still-to-be-written
+// configuration functions.
+
+// Define all base resources. This should be called by census initialization.
+void define_base_resources() {
+  google_census_Resource_BasicUnit numerator =
+      google_census_Resource_BasicUnit_SECS;
+  resource r = {"client_rpc_latency",             // name
+                "Client RPC latency in seconds",  // description
+                0,                                // prefix
+                1,                                // n_numerators
+                &numerator,                       // numerators
+                0,                                // n_denominators
+                NULL};                            // denominators
+  define_resource(&r);
+  r = (resource){"server_rpc_latency",             // name
+                 "Server RPC latency in seconds",  // description
+                 0,                                // prefix
+                 1,                                // n_numerators
+                 &numerator,                       // numerators
+                 0,                                // n_denominators
+                 NULL};                            // denominators
+  define_resource(&r);
+}
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/src/core/ext/census/base_resources.h
similarity index 70%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to src/core/ext/census/base_resources.h
index df2324c..e5a7696 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/src/core/ext/census/base_resources.h
@@ -1,6 +1,5 @@
 /*
- *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +30,10 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#ifndef GRPC_CORE_EXT_CENSUS_BASE_RESOURCES_H
+#define GRPC_CORE_EXT_CENSUS_BASE_RESOURCES_H
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+/* Define all base resources. This should be called by census initialization. */
+void define_base_resources();
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
-
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
-
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+#endif /* GRPC_CORE_EXT_CENSUS_BASE_RESOURCES_H */
diff --git a/src/core/ext/census/gen/census.pb.c b/src/core/ext/census/gen/census.pb.c
index d614636..647f063 100644
--- a/src/core/ext/census/gen/census.pb.c
+++ b/src/core/ext/census/gen/census.pb.c
@@ -53,29 +53,24 @@
     PB_LAST_FIELD
 };
 
-const pb_field_t google_census_Metric_fields[5] = {
-    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, google_census_Metric, name, name, 0),
-    PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, google_census_Metric, description, name, 0),
-    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_Metric, unit, description, &google_census_Metric_MeasurementUnit_fields),
-    PB_FIELD(  4, INT32   , OPTIONAL, STATIC  , OTHER, google_census_Metric, id, unit, 0),
+const pb_field_t google_census_Resource_fields[4] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, google_census_Resource, name, name, 0),
+    PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, google_census_Resource, description, name, 0),
+    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_Resource, unit, description, &google_census_Resource_MeasurementUnit_fields),
     PB_LAST_FIELD
 };
 
-const pb_field_t google_census_Metric_BasicUnit_fields[2] = {
-    PB_FIELD(  1, UENUM   , OPTIONAL, STATIC  , FIRST, google_census_Metric_BasicUnit, type, type, 0),
+const pb_field_t google_census_Resource_MeasurementUnit_fields[4] = {
+    PB_FIELD(  1, INT32   , OPTIONAL, STATIC  , FIRST, google_census_Resource_MeasurementUnit, prefix, prefix, 0),
+    PB_FIELD(  2, UENUM   , REPEATED, CALLBACK, OTHER, google_census_Resource_MeasurementUnit, numerator, prefix, 0),
+    PB_FIELD(  3, UENUM   , REPEATED, CALLBACK, OTHER, google_census_Resource_MeasurementUnit, denominator, numerator, 0),
     PB_LAST_FIELD
 };
 
-const pb_field_t google_census_Metric_MeasurementUnit_fields[4] = {
-    PB_FIELD(  1, INT32   , OPTIONAL, STATIC  , FIRST, google_census_Metric_MeasurementUnit, prefix, prefix, 0),
-    PB_FIELD(  2, MESSAGE , REPEATED, CALLBACK, OTHER, google_census_Metric_MeasurementUnit, numerator, prefix, &google_census_Metric_BasicUnit_fields),
-    PB_FIELD(  3, MESSAGE , REPEATED, CALLBACK, OTHER, google_census_Metric_MeasurementUnit, denominator, numerator, &google_census_Metric_BasicUnit_fields),
-    PB_LAST_FIELD
-};
-
-const pb_field_t google_census_AggregationDescriptor_fields[3] = {
-    PB_ONEOF_FIELD(options,   1, MESSAGE , ONEOF, STATIC  , FIRST, google_census_AggregationDescriptor, bucket_boundaries, bucket_boundaries, &google_census_AggregationDescriptor_BucketBoundaries_fields),
-    PB_ONEOF_FIELD(options,   2, MESSAGE , ONEOF, STATIC  , FIRST, google_census_AggregationDescriptor, interval_boundaries, interval_boundaries, &google_census_AggregationDescriptor_IntervalBoundaries_fields),
+const pb_field_t google_census_AggregationDescriptor_fields[4] = {
+    PB_FIELD(  1, UENUM   , OPTIONAL, STATIC  , FIRST, google_census_AggregationDescriptor, type, type, 0),
+    PB_ONEOF_FIELD(options,   2, MESSAGE , ONEOF, STATIC  , OTHER, google_census_AggregationDescriptor, bucket_boundaries, type, &google_census_AggregationDescriptor_BucketBoundaries_fields),
+    PB_ONEOF_FIELD(options,   3, MESSAGE , ONEOF, STATIC  , OTHER, google_census_AggregationDescriptor, interval_boundaries, type, &google_census_AggregationDescriptor_IntervalBoundaries_fields),
     PB_LAST_FIELD
 };
 
@@ -124,25 +119,27 @@
 const pb_field_t google_census_View_fields[6] = {
     PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, google_census_View, name, name, 0),
     PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, google_census_View, description, name, 0),
-    PB_FIELD(  3, INT32   , OPTIONAL, STATIC  , OTHER, google_census_View, metric_id, description, 0),
-    PB_FIELD(  4, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_View, aggregation, metric_id, &google_census_AggregationDescriptor_fields),
+    PB_FIELD(  3, STRING  , OPTIONAL, CALLBACK, OTHER, google_census_View, resource_name, description, 0),
+    PB_FIELD(  4, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_View, aggregation, resource_name, &google_census_AggregationDescriptor_fields),
     PB_FIELD(  5, STRING  , REPEATED, CALLBACK, OTHER, google_census_View, tag_key, aggregation, 0),
     PB_LAST_FIELD
 };
 
-const pb_field_t google_census_Aggregation_fields[6] = {
+const pb_field_t google_census_Aggregation_fields[7] = {
     PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, google_census_Aggregation, name, name, 0),
     PB_FIELD(  2, STRING  , OPTIONAL, CALLBACK, OTHER, google_census_Aggregation, description, name, 0),
-    PB_ONEOF_FIELD(data,   3, MESSAGE , ONEOF, STATIC  , OTHER, google_census_Aggregation, distribution, description, &google_census_Distribution_fields),
-    PB_ONEOF_FIELD(data,   4, MESSAGE , ONEOF, STATIC  , OTHER, google_census_Aggregation, interval_stats, description, &google_census_IntervalStats_fields),
-    PB_FIELD(  5, MESSAGE , REPEATED, CALLBACK, OTHER, google_census_Aggregation, tag, data.interval_stats, &google_census_Tag_fields),
+    PB_ONEOF_FIELD(data,   3, UINT64  , ONEOF, STATIC  , OTHER, google_census_Aggregation, count, description, 0),
+    PB_ONEOF_FIELD(data,   4, MESSAGE , ONEOF, STATIC  , OTHER, google_census_Aggregation, distribution, description, &google_census_Distribution_fields),
+    PB_ONEOF_FIELD(data,   5, MESSAGE , ONEOF, STATIC  , OTHER, google_census_Aggregation, interval_stats, description, &google_census_IntervalStats_fields),
+    PB_FIELD(  6, MESSAGE , REPEATED, CALLBACK, OTHER, google_census_Aggregation, tag, data.interval_stats, &google_census_Tag_fields),
     PB_LAST_FIELD
 };
 
-const pb_field_t google_census_ViewAggregations_fields[4] = {
-    PB_FIELD(  1, MESSAGE , REPEATED, CALLBACK, FIRST, google_census_ViewAggregations, aggregation, aggregation, &google_census_Aggregation_fields),
-    PB_FIELD(  2, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_ViewAggregations, start, aggregation, &google_census_Timestamp_fields),
-    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_ViewAggregations, end, start, &google_census_Timestamp_fields),
+const pb_field_t google_census_Metric_fields[5] = {
+    PB_FIELD(  1, STRING  , OPTIONAL, CALLBACK, FIRST, google_census_Metric, view_name, view_name, 0),
+    PB_FIELD(  2, MESSAGE , REPEATED, CALLBACK, OTHER, google_census_Metric, aggregation, view_name, &google_census_Aggregation_fields),
+    PB_FIELD(  3, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_Metric, start, aggregation, &google_census_Timestamp_fields),
+    PB_FIELD(  4, MESSAGE , OPTIONAL, STATIC  , OTHER, google_census_Metric, end, start, &google_census_Timestamp_fields),
     PB_LAST_FIELD
 };
 
@@ -156,7 +153,7 @@
  * numbers or field sizes that are larger than what can fit in 8 or 16 bit
  * field descriptors.
  */
-PB_STATIC_ASSERT((pb_membersize(google_census_Metric, unit) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Metric, unit) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Distribution, range) < 65536 && pb_membersize(google_census_IntervalStats, window) < 65536 && pb_membersize(google_census_IntervalStats_Window, window_size) < 65536 && pb_membersize(google_census_View, aggregation) < 65536 && pb_membersize(google_census_Aggregation, data.distribution) < 65536 && pb_membersize(google_census_Aggregation, data.interval_stats) < 65536 && pb_membersize(google_census_Metric, unit) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Metric, unit) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 65536 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Distribution, range) < 65536 && pb_membersize(google_census_IntervalStats, window) < 65536 && pb_membersize(google_census_IntervalStats_Window, window_size) < 65536 && pb_membersize(google_census_View, aggregation) < 65536 && pb_membersize(google_census_Aggregation, data.distribution) < 65536 && pb_membersize(google_census_Aggregation, data.interval_stats) < 65536 && pb_membersize(google_census_Aggregation, tag) < 65536 && pb_membersize(google_census_ViewAggregations, aggregation) < 65536 && pb_membersize(google_census_ViewAggregations, start) < 65536 && pb_membersize(google_census_ViewAggregations, end) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_census_Duration_google_census_Timestamp_google_census_Metric_google_census_Metric_BasicUnit_google_census_Metric_MeasurementUnit_google_census_AggregationDescriptor_google_census_AggregationDescriptor_BucketBoundaries_google_census_AggregationDescriptor_IntervalBoundaries_google_census_Distribution_google_census_Distribution_Range_google_census_IntervalStats_google_census_IntervalStats_Window_google_census_Tag_google_census_View_google_census_Aggregation_google_census_ViewAggregations)
+PB_STATIC_ASSERT((pb_membersize(google_census_Resource, unit) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Resource, unit) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Distribution, range) < 65536 && pb_membersize(google_census_IntervalStats, window) < 65536 && pb_membersize(google_census_IntervalStats_Window, window_size) < 65536 && pb_membersize(google_census_View, aggregation) < 65536 && pb_membersize(google_census_Aggregation, data.distribution) < 65536 && pb_membersize(google_census_Aggregation, data.interval_stats) < 65536 && pb_membersize(google_census_Resource, unit) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Resource, unit) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 65536 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 65536 && pb_membersize(google_census_Distribution, range) < 65536 && pb_membersize(google_census_IntervalStats, window) < 65536 && pb_membersize(google_census_IntervalStats_Window, window_size) < 65536 && pb_membersize(google_census_View, aggregation) < 65536 && pb_membersize(google_census_Aggregation, data.distribution) < 65536 && pb_membersize(google_census_Aggregation, data.interval_stats) < 65536 && pb_membersize(google_census_Aggregation, tag) < 65536 && pb_membersize(google_census_Metric, aggregation) < 65536 && pb_membersize(google_census_Metric, start) < 65536 && pb_membersize(google_census_Metric, end) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_census_Duration_google_census_Timestamp_google_census_Resource_google_census_Resource_MeasurementUnit_google_census_AggregationDescriptor_google_census_AggregationDescriptor_BucketBoundaries_google_census_AggregationDescriptor_IntervalBoundaries_google_census_Distribution_google_census_Distribution_Range_google_census_IntervalStats_google_census_IntervalStats_Window_google_census_Tag_google_census_View_google_census_Aggregation_google_census_Metric)
 #endif
 
 #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
@@ -167,7 +164,7 @@
  * numbers or field sizes that are larger than what can fit in the default
  * 8 bit descriptors.
  */
-PB_STATIC_ASSERT((pb_membersize(google_census_Metric, unit) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Metric, unit) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Distribution, range) < 256 && pb_membersize(google_census_IntervalStats, window) < 256 && pb_membersize(google_census_IntervalStats_Window, window_size) < 256 && pb_membersize(google_census_View, aggregation) < 256 && pb_membersize(google_census_Aggregation, data.distribution) < 256 && pb_membersize(google_census_Aggregation, data.interval_stats) < 256 && pb_membersize(google_census_Metric, unit) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Metric, unit) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, numerator) < 256 && pb_membersize(google_census_Metric_MeasurementUnit, denominator) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Distribution, range) < 256 && pb_membersize(google_census_IntervalStats, window) < 256 && pb_membersize(google_census_IntervalStats_Window, window_size) < 256 && pb_membersize(google_census_View, aggregation) < 256 && pb_membersize(google_census_Aggregation, data.distribution) < 256 && pb_membersize(google_census_Aggregation, data.interval_stats) < 256 && pb_membersize(google_census_Aggregation, tag) < 256 && pb_membersize(google_census_ViewAggregations, aggregation) < 256 && pb_membersize(google_census_ViewAggregations, start) < 256 && pb_membersize(google_census_ViewAggregations, end) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_census_Duration_google_census_Timestamp_google_census_Metric_google_census_Metric_BasicUnit_google_census_Metric_MeasurementUnit_google_census_AggregationDescriptor_google_census_AggregationDescriptor_BucketBoundaries_google_census_AggregationDescriptor_IntervalBoundaries_google_census_Distribution_google_census_Distribution_Range_google_census_IntervalStats_google_census_IntervalStats_Window_google_census_Tag_google_census_View_google_census_Aggregation_google_census_ViewAggregations)
+PB_STATIC_ASSERT((pb_membersize(google_census_Resource, unit) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Resource, unit) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Distribution, range) < 256 && pb_membersize(google_census_IntervalStats, window) < 256 && pb_membersize(google_census_IntervalStats_Window, window_size) < 256 && pb_membersize(google_census_View, aggregation) < 256 && pb_membersize(google_census_Aggregation, data.distribution) < 256 && pb_membersize(google_census_Aggregation, data.interval_stats) < 256 && pb_membersize(google_census_Resource, unit) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Resource, unit) < 256 && pb_membersize(google_census_AggregationDescriptor, options.bucket_boundaries) < 256 && pb_membersize(google_census_AggregationDescriptor, options.interval_boundaries) < 256 && pb_membersize(google_census_Distribution, range) < 256 && pb_membersize(google_census_IntervalStats, window) < 256 && pb_membersize(google_census_IntervalStats_Window, window_size) < 256 && pb_membersize(google_census_View, aggregation) < 256 && pb_membersize(google_census_Aggregation, data.distribution) < 256 && pb_membersize(google_census_Aggregation, data.interval_stats) < 256 && pb_membersize(google_census_Aggregation, tag) < 256 && pb_membersize(google_census_Metric, aggregation) < 256 && pb_membersize(google_census_Metric, start) < 256 && pb_membersize(google_census_Metric, end) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_census_Duration_google_census_Timestamp_google_census_Resource_google_census_Resource_MeasurementUnit_google_census_AggregationDescriptor_google_census_AggregationDescriptor_BucketBoundaries_google_census_AggregationDescriptor_IntervalBoundaries_google_census_Distribution_google_census_Distribution_Range_google_census_IntervalStats_google_census_IntervalStats_Window_google_census_Tag_google_census_View_google_census_Aggregation_google_census_Metric)
 #endif
 
 
diff --git a/src/core/ext/census/gen/census.pb.h b/src/core/ext/census/gen/census.pb.h
index d040fe2..dae583f 100644
--- a/src/core/ext/census/gen/census.pb.h
+++ b/src/core/ext/census/gen/census.pb.h
@@ -45,14 +45,21 @@
 #endif
 
 /* Enum definitions */
-typedef enum _google_census_Metric_BasicUnit_Measure {
-    google_census_Metric_BasicUnit_Measure_UNKNOWN = 0,
-    google_census_Metric_BasicUnit_Measure_BITS = 1,
-    google_census_Metric_BasicUnit_Measure_BYTES = 2,
-    google_census_Metric_BasicUnit_Measure_SECS = 3,
-    google_census_Metric_BasicUnit_Measure_CORES = 4,
-    google_census_Metric_BasicUnit_Measure_MAX_UNITS = 5
-} google_census_Metric_BasicUnit_Measure;
+typedef enum _google_census_Resource_BasicUnit {
+    google_census_Resource_BasicUnit_UNKNOWN = 0,
+    google_census_Resource_BasicUnit_BITS = 1,
+    google_census_Resource_BasicUnit_BYTES = 2,
+    google_census_Resource_BasicUnit_SECS = 3,
+    google_census_Resource_BasicUnit_CORES = 4,
+    google_census_Resource_BasicUnit_MAX_UNITS = 5
+} google_census_Resource_BasicUnit;
+
+typedef enum _google_census_AggregationDescriptor_AggregationType {
+    google_census_AggregationDescriptor_AggregationType_UNKNOWN = 0,
+    google_census_AggregationDescriptor_AggregationType_COUNT = 1,
+    google_census_AggregationDescriptor_AggregationType_DISTRIBUTION = 2,
+    google_census_AggregationDescriptor_AggregationType_INTERVAL = 3
+} google_census_AggregationDescriptor_AggregationType;
 
 /* Struct definitions */
 typedef struct _google_census_AggregationDescriptor_BucketBoundaries {
@@ -68,6 +75,8 @@
 } google_census_IntervalStats;
 
 typedef struct _google_census_AggregationDescriptor {
+    bool has_type;
+    google_census_AggregationDescriptor_AggregationType type;
     pb_size_t which_options;
     union {
         google_census_AggregationDescriptor_BucketBoundaries bucket_boundaries;
@@ -89,17 +98,12 @@
     int32_t nanos;
 } google_census_Duration;
 
-typedef struct _google_census_Metric_BasicUnit {
-    bool has_type;
-    google_census_Metric_BasicUnit_Measure type;
-} google_census_Metric_BasicUnit;
-
-typedef struct _google_census_Metric_MeasurementUnit {
+typedef struct _google_census_Resource_MeasurementUnit {
     bool has_prefix;
     int32_t prefix;
     pb_callback_t numerator;
     pb_callback_t denominator;
-} google_census_Metric_MeasurementUnit;
+} google_census_Resource_MeasurementUnit;
 
 typedef struct _google_census_Tag {
     bool has_key;
@@ -135,37 +139,36 @@
 } google_census_IntervalStats_Window;
 
 typedef struct _google_census_Metric {
-    pb_callback_t name;
-    pb_callback_t description;
-    bool has_unit;
-    google_census_Metric_MeasurementUnit unit;
-    bool has_id;
-    int32_t id;
-} google_census_Metric;
-
-typedef struct _google_census_View {
-    pb_callback_t name;
-    pb_callback_t description;
-    bool has_metric_id;
-    int32_t metric_id;
-    bool has_aggregation;
-    google_census_AggregationDescriptor aggregation;
-    pb_callback_t tag_key;
-} google_census_View;
-
-typedef struct _google_census_ViewAggregations {
+    pb_callback_t view_name;
     pb_callback_t aggregation;
     bool has_start;
     google_census_Timestamp start;
     bool has_end;
     google_census_Timestamp end;
-} google_census_ViewAggregations;
+} google_census_Metric;
+
+typedef struct _google_census_Resource {
+    pb_callback_t name;
+    pb_callback_t description;
+    bool has_unit;
+    google_census_Resource_MeasurementUnit unit;
+} google_census_Resource;
+
+typedef struct _google_census_View {
+    pb_callback_t name;
+    pb_callback_t description;
+    pb_callback_t resource_name;
+    bool has_aggregation;
+    google_census_AggregationDescriptor aggregation;
+    pb_callback_t tag_key;
+} google_census_View;
 
 typedef struct _google_census_Aggregation {
     pb_callback_t name;
     pb_callback_t description;
     pb_size_t which_data;
     union {
+        uint64_t count;
         google_census_Distribution distribution;
         google_census_IntervalStats interval_stats;
     } data;
@@ -177,10 +180,9 @@
 /* Initializer values for message structs */
 #define google_census_Duration_init_default      {false, 0, false, 0}
 #define google_census_Timestamp_init_default     {false, 0, false, 0}
-#define google_census_Metric_init_default        {{{NULL}, NULL}, {{NULL}, NULL}, false, google_census_Metric_MeasurementUnit_init_default, false, 0}
-#define google_census_Metric_BasicUnit_init_default {false, (google_census_Metric_BasicUnit_Measure)0}
-#define google_census_Metric_MeasurementUnit_init_default {false, 0, {{NULL}, NULL}, {{NULL}, NULL}}
-#define google_census_AggregationDescriptor_init_default {0, {google_census_AggregationDescriptor_BucketBoundaries_init_default}}
+#define google_census_Resource_init_default      {{{NULL}, NULL}, {{NULL}, NULL}, false, google_census_Resource_MeasurementUnit_init_default}
+#define google_census_Resource_MeasurementUnit_init_default {false, 0, {{NULL}, NULL}, {{NULL}, NULL}}
+#define google_census_AggregationDescriptor_init_default {false, (google_census_AggregationDescriptor_AggregationType)0, 0, {google_census_AggregationDescriptor_BucketBoundaries_init_default}}
 #define google_census_AggregationDescriptor_BucketBoundaries_init_default {{{NULL}, NULL}}
 #define google_census_AggregationDescriptor_IntervalBoundaries_init_default {{{NULL}, NULL}}
 #define google_census_Distribution_init_default  {false, 0, false, 0, false, google_census_Distribution_Range_init_default, {{NULL}, NULL}}
@@ -188,15 +190,14 @@
 #define google_census_IntervalStats_init_default {{{NULL}, NULL}}
 #define google_census_IntervalStats_Window_init_default {false, google_census_Duration_init_default, false, 0, false, 0}
 #define google_census_Tag_init_default           {false, "", false, ""}
-#define google_census_View_init_default          {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, google_census_AggregationDescriptor_init_default, {{NULL}, NULL}}
-#define google_census_Aggregation_init_default   {{{NULL}, NULL}, {{NULL}, NULL}, 0, {google_census_Distribution_init_default}, {{NULL}, NULL}}
-#define google_census_ViewAggregations_init_default {{{NULL}, NULL}, false, google_census_Timestamp_init_default, false, google_census_Timestamp_init_default}
+#define google_census_View_init_default          {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, google_census_AggregationDescriptor_init_default, {{NULL}, NULL}}
+#define google_census_Aggregation_init_default   {{{NULL}, NULL}, {{NULL}, NULL}, 0, {0}, {{NULL}, NULL}}
+#define google_census_Metric_init_default        {{{NULL}, NULL}, {{NULL}, NULL}, false, google_census_Timestamp_init_default, false, google_census_Timestamp_init_default}
 #define google_census_Duration_init_zero         {false, 0, false, 0}
 #define google_census_Timestamp_init_zero        {false, 0, false, 0}
-#define google_census_Metric_init_zero           {{{NULL}, NULL}, {{NULL}, NULL}, false, google_census_Metric_MeasurementUnit_init_zero, false, 0}
-#define google_census_Metric_BasicUnit_init_zero {false, (google_census_Metric_BasicUnit_Measure)0}
-#define google_census_Metric_MeasurementUnit_init_zero {false, 0, {{NULL}, NULL}, {{NULL}, NULL}}
-#define google_census_AggregationDescriptor_init_zero {0, {google_census_AggregationDescriptor_BucketBoundaries_init_zero}}
+#define google_census_Resource_init_zero         {{{NULL}, NULL}, {{NULL}, NULL}, false, google_census_Resource_MeasurementUnit_init_zero}
+#define google_census_Resource_MeasurementUnit_init_zero {false, 0, {{NULL}, NULL}, {{NULL}, NULL}}
+#define google_census_AggregationDescriptor_init_zero {false, (google_census_AggregationDescriptor_AggregationType)0, 0, {google_census_AggregationDescriptor_BucketBoundaries_init_zero}}
 #define google_census_AggregationDescriptor_BucketBoundaries_init_zero {{{NULL}, NULL}}
 #define google_census_AggregationDescriptor_IntervalBoundaries_init_zero {{{NULL}, NULL}}
 #define google_census_Distribution_init_zero     {false, 0, false, 0, false, google_census_Distribution_Range_init_zero, {{NULL}, NULL}}
@@ -204,25 +205,25 @@
 #define google_census_IntervalStats_init_zero    {{{NULL}, NULL}}
 #define google_census_IntervalStats_Window_init_zero {false, google_census_Duration_init_zero, false, 0, false, 0}
 #define google_census_Tag_init_zero              {false, "", false, ""}
-#define google_census_View_init_zero             {{{NULL}, NULL}, {{NULL}, NULL}, false, 0, false, google_census_AggregationDescriptor_init_zero, {{NULL}, NULL}}
-#define google_census_Aggregation_init_zero      {{{NULL}, NULL}, {{NULL}, NULL}, 0, {google_census_Distribution_init_zero}, {{NULL}, NULL}}
-#define google_census_ViewAggregations_init_zero {{{NULL}, NULL}, false, google_census_Timestamp_init_zero, false, google_census_Timestamp_init_zero}
+#define google_census_View_init_zero             {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, google_census_AggregationDescriptor_init_zero, {{NULL}, NULL}}
+#define google_census_Aggregation_init_zero      {{{NULL}, NULL}, {{NULL}, NULL}, 0, {0}, {{NULL}, NULL}}
+#define google_census_Metric_init_zero           {{{NULL}, NULL}, {{NULL}, NULL}, false, google_census_Timestamp_init_zero, false, google_census_Timestamp_init_zero}
 
 /* Field tags (for use in manual encoding/decoding) */
 #define google_census_AggregationDescriptor_BucketBoundaries_bounds_tag 1
 #define google_census_AggregationDescriptor_IntervalBoundaries_window_size_tag 1
 #define google_census_IntervalStats_window_tag   1
-#define google_census_AggregationDescriptor_bucket_boundaries_tag 1
+#define google_census_AggregationDescriptor_bucket_boundaries_tag 2
 
-#define google_census_AggregationDescriptor_interval_boundaries_tag 2
+#define google_census_AggregationDescriptor_interval_boundaries_tag 3
+#define google_census_AggregationDescriptor_type_tag 1
 #define google_census_Distribution_Range_min_tag 1
 #define google_census_Distribution_Range_max_tag 2
 #define google_census_Duration_seconds_tag       1
 #define google_census_Duration_nanos_tag         2
-#define google_census_Metric_BasicUnit_type_tag  1
-#define google_census_Metric_MeasurementUnit_prefix_tag 1
-#define google_census_Metric_MeasurementUnit_numerator_tag 2
-#define google_census_Metric_MeasurementUnit_denominator_tag 3
+#define google_census_Resource_MeasurementUnit_prefix_tag 1
+#define google_census_Resource_MeasurementUnit_numerator_tag 2
+#define google_census_Resource_MeasurementUnit_denominator_tag 3
 #define google_census_Tag_key_tag                1
 #define google_census_Tag_value_tag              2
 #define google_census_Timestamp_seconds_tag      1
@@ -234,32 +235,33 @@
 #define google_census_IntervalStats_Window_window_size_tag 1
 #define google_census_IntervalStats_Window_count_tag 2
 #define google_census_IntervalStats_Window_mean_tag 3
-#define google_census_Metric_name_tag            1
-#define google_census_Metric_description_tag     2
-#define google_census_Metric_unit_tag            3
-#define google_census_Metric_id_tag              4
+#define google_census_Metric_view_name_tag       1
+#define google_census_Metric_aggregation_tag     2
+#define google_census_Metric_start_tag           3
+#define google_census_Metric_end_tag             4
+#define google_census_Resource_name_tag          1
+#define google_census_Resource_description_tag   2
+#define google_census_Resource_unit_tag          3
 #define google_census_View_name_tag              1
 #define google_census_View_description_tag       2
-#define google_census_View_metric_id_tag         3
+#define google_census_View_resource_name_tag     3
 #define google_census_View_aggregation_tag       4
 #define google_census_View_tag_key_tag           5
-#define google_census_ViewAggregations_aggregation_tag 1
-#define google_census_ViewAggregations_start_tag 2
-#define google_census_ViewAggregations_end_tag   3
-#define google_census_Aggregation_distribution_tag 3
+#define google_census_Aggregation_count_tag      3
 
-#define google_census_Aggregation_interval_stats_tag 4
+#define google_census_Aggregation_distribution_tag 4
+
+#define google_census_Aggregation_interval_stats_tag 5
 #define google_census_Aggregation_name_tag       1
 #define google_census_Aggregation_description_tag 2
-#define google_census_Aggregation_tag_tag        5
+#define google_census_Aggregation_tag_tag        6
 
 /* Struct field encoding specification for nanopb */
 extern const pb_field_t google_census_Duration_fields[3];
 extern const pb_field_t google_census_Timestamp_fields[3];
-extern const pb_field_t google_census_Metric_fields[5];
-extern const pb_field_t google_census_Metric_BasicUnit_fields[2];
-extern const pb_field_t google_census_Metric_MeasurementUnit_fields[4];
-extern const pb_field_t google_census_AggregationDescriptor_fields[3];
+extern const pb_field_t google_census_Resource_fields[4];
+extern const pb_field_t google_census_Resource_MeasurementUnit_fields[4];
+extern const pb_field_t google_census_AggregationDescriptor_fields[4];
 extern const pb_field_t google_census_AggregationDescriptor_BucketBoundaries_fields[2];
 extern const pb_field_t google_census_AggregationDescriptor_IntervalBoundaries_fields[2];
 extern const pb_field_t google_census_Distribution_fields[5];
@@ -268,13 +270,12 @@
 extern const pb_field_t google_census_IntervalStats_Window_fields[4];
 extern const pb_field_t google_census_Tag_fields[3];
 extern const pb_field_t google_census_View_fields[6];
-extern const pb_field_t google_census_Aggregation_fields[6];
-extern const pb_field_t google_census_ViewAggregations_fields[4];
+extern const pb_field_t google_census_Aggregation_fields[7];
+extern const pb_field_t google_census_Metric_fields[5];
 
 /* Maximum encoded size of messages (where known) */
 #define google_census_Duration_size              22
 #define google_census_Timestamp_size             22
-#define google_census_Metric_BasicUnit_size      2
 #define google_census_Distribution_Range_size    18
 #define google_census_IntervalStats_Window_size  44
 #define google_census_Tag_size                   516
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index f51d850..9dacc17 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -127,38 +127,40 @@
   grpc_call_next_op(exec_ctx, elem, op);
 }
 
-static void client_init_call_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_call_element_args *args) {
+static grpc_error *client_init_call_elem(grpc_exec_ctx *exec_ctx,
+                                         grpc_call_element *elem,
+                                         grpc_call_element_args *args) {
   call_data *d = elem->call_data;
   GPR_ASSERT(d != NULL);
   memset(d, 0, sizeof(*d));
   d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
+  return GRPC_ERROR_NONE;
 }
 
 static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
                                      grpc_call_element *elem,
-                                     const grpc_call_stats *stats,
+                                     const grpc_call_final_info *final_info,
                                      void *ignored) {
   call_data *d = elem->call_data;
   GPR_ASSERT(d != NULL);
   /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
 }
 
-static void server_init_call_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_call_element_args *args) {
+static grpc_error *server_init_call_elem(grpc_exec_ctx *exec_ctx,
+                                         grpc_call_element *elem,
+                                         grpc_call_element_args *args) {
   call_data *d = elem->call_data;
   GPR_ASSERT(d != NULL);
   memset(d, 0, sizeof(*d));
   d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
   /* TODO(hongyu): call census_tracing_start_op here. */
   grpc_closure_init(&d->finish_recv, server_on_done_recv, elem);
+  return GRPC_ERROR_NONE;
 }
 
 static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
                                      grpc_call_element *elem,
-                                     const grpc_call_stats *stats,
+                                     const grpc_call_final_info *final_info,
                                      void *ignored) {
   call_data *d = elem->call_data;
   GPR_ASSERT(d != NULL);
diff --git a/src/core/ext/census/initialize.c b/src/core/ext/census/initialize.c
index 896276e..55cbbe8 100644
--- a/src/core/ext/census/initialize.c
+++ b/src/core/ext/census/initialize.c
@@ -32,19 +32,31 @@
  */
 
 #include <grpc/census.h>
+#include "src/core/ext/census/base_resources.h"
+#include "src/core/ext/census/resource.h"
 
 static int features_enabled = CENSUS_FEATURE_NONE;
 
 int census_initialize(int features) {
   if (features_enabled != CENSUS_FEATURE_NONE) {
     // Must have been a previous call to census_initialize; return error
-    return 1;
+    return -1;
   }
-  features_enabled = features;
-  return 0;
+  features_enabled = features & CENSUS_FEATURE_ALL;
+  if (features & CENSUS_FEATURE_STATS) {
+    initialize_resources();
+    define_base_resources();
+  }
+
+  return features_enabled;
 }
 
-void census_shutdown(void) { features_enabled = CENSUS_FEATURE_NONE; }
+void census_shutdown(void) {
+  if (features_enabled & CENSUS_FEATURE_STATS) {
+    shutdown_resources();
+  }
+  features_enabled = CENSUS_FEATURE_NONE;
+}
 
 int census_supported(void) {
   /* TODO(aveitch): improve this as we implement features... */
diff --git a/src/core/ext/census/placeholders.c b/src/core/ext/census/placeholders.c
index fe23d13..9f99c5b 100644
--- a/src/core/ext/census/placeholders.c
+++ b/src/core/ext/census/placeholders.c
@@ -62,48 +62,3 @@
   (void)consume;
   abort();
 }
-
-const census_aggregation *census_view_aggregrations(const census_view *view) {
-  (void)view;
-  abort();
-}
-
-census_view *census_view_create(uint32_t metric_id, const census_context *tags,
-                                const census_aggregation *aggregations,
-                                size_t naggregations) {
-  (void)metric_id;
-  (void)tags;
-  (void)aggregations;
-  (void)naggregations;
-  abort();
-}
-
-const census_context *census_view_tags(const census_view *view) {
-  (void)view;
-  abort();
-}
-
-void census_view_delete(census_view *view) {
-  (void)view;
-  abort();
-}
-
-const census_view_data *census_view_get_data(const census_view *view) {
-  (void)view;
-  abort();
-}
-
-size_t census_view_metric(const census_view *view) {
-  (void)view;
-  abort();
-}
-
-size_t census_view_naggregations(const census_view *view) {
-  (void)view;
-  abort();
-}
-
-void census_view_reset(census_view *view) {
-  (void)view;
-  abort();
-}
diff --git a/src/core/ext/census/resource.c b/src/core/ext/census/resource.c
new file mode 100644
index 0000000..ed44f00
--- /dev/null
+++ b/src/core/ext/census/resource.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * 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/ext/census/resource.h"
+#include "third_party/nanopb/pb_decode.h"
+
+#include <grpc/census.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include <stdbool.h>
+#include <string.h>
+
+// Protect local resource data structures.
+static gpr_mu resource_lock;
+
+// Deleteing and creating resources are relatively rare events, and should not
+// be done in the critical path of performance sensitive code. We record
+// current resource id's used in a simple array, and just search it each time
+// we need to assign a new id, or look up a resource.
+static resource **resources = NULL;
+
+// Number of entries in *resources
+static size_t n_resources = 0;
+
+// Number of defined resources
+static size_t n_defined_resources = 0;
+
+void initialize_resources(void) {
+  gpr_mu_init(&resource_lock);
+  gpr_mu_lock(&resource_lock);
+  GPR_ASSERT(resources == NULL && n_resources == 0 && n_defined_resources == 0);
+  gpr_mu_unlock(&resource_lock);
+}
+
+// Delete a resource given it's ID. The ID must be a valid resource ID. Must be
+// called with resource_lock held.
+static void delete_resource_locked(size_t rid) {
+  GPR_ASSERT(resources[rid] != NULL);
+  gpr_free(resources[rid]->name);
+  gpr_free(resources[rid]->description);
+  gpr_free(resources[rid]->numerators);
+  gpr_free(resources[rid]->denominators);
+  gpr_free(resources[rid]);
+  resources[rid] = NULL;
+  n_defined_resources--;
+}
+
+void shutdown_resources(void) {
+  gpr_mu_lock(&resource_lock);
+  for (size_t i = 0; i < n_resources; i++) {
+    if (resources[i] != NULL) {
+      delete_resource_locked(i);
+    }
+  }
+  GPR_ASSERT(n_defined_resources == 0);
+  gpr_free(resources);
+  resources = NULL;
+  n_resources = 0;
+  gpr_mu_unlock(&resource_lock);
+}
+
+// Check the contents of string fields in a resource proto.
+static bool validate_string(pb_istream_t *stream, const pb_field_t *field,
+                            void **arg) {
+  resource *vresource = (resource *)*arg;
+  switch (field->tag) {
+    case google_census_Resource_name_tag:
+      // Name must have at least one character
+      if (stream->bytes_left == 0) {
+        gpr_log(GPR_INFO, "Zero-length Resource name.");
+        return false;
+      }
+      vresource->name = gpr_malloc(stream->bytes_left + 1);
+      vresource->name[stream->bytes_left] = '\0';
+      if (!pb_read(stream, (uint8_t *)vresource->name, stream->bytes_left)) {
+        return false;
+      }
+      // Can't have same name as an existing resource.
+      for (size_t i = 0; i < n_resources; i++) {
+        resource *compare = resources[i];
+        if (compare == vresource || compare == NULL) continue;
+        if (strcmp(compare->name, vresource->name) == 0) {
+          gpr_log(GPR_INFO, "Duplicate Resource name %s.", vresource->name);
+          return false;
+        }
+      }
+      break;
+    case google_census_Resource_description_tag:
+      if (stream->bytes_left == 0) {
+        return true;
+      }
+      vresource->description = gpr_malloc(stream->bytes_left + 1);
+      vresource->description[stream->bytes_left] = '\0';
+      if (!pb_read(stream, (uint8_t *)vresource->description,
+                   stream->bytes_left)) {
+        return false;
+      }
+      break;
+    default:
+      // No other string fields in Resource. Print warning and skip.
+      gpr_log(GPR_INFO, "Unknown string field type in Resource protobuf.");
+      if (!pb_read(stream, NULL, stream->bytes_left)) {
+        return false;
+      }
+      break;
+  }
+  return true;
+}
+
+// Decode numerators/denominators in a stream. The `count` and `bup`
+// (BasicUnit pointer) are pointers to the approriate fields in a resource
+// struct.
+static bool validate_units_helper(pb_istream_t *stream, int *count,
+                                  google_census_Resource_BasicUnit **bup) {
+  while (stream->bytes_left) {
+    (*count)++;
+    // Have to allocate a new array of values. Normal case is 0 or 1, so
+    // this should normally not be an issue.
+    google_census_Resource_BasicUnit *new_bup =
+        gpr_malloc((size_t)*count * sizeof(google_census_Resource_BasicUnit));
+    if (*count != 1) {
+      memcpy(new_bup, *bup,
+             (size_t)(*count - 1) * sizeof(google_census_Resource_BasicUnit));
+      gpr_free(*bup);
+    }
+    *bup = new_bup;
+    uint64_t value;
+    if (!pb_decode_varint(stream, &value)) {
+      return false;
+    }
+    *(*bup + *count - 1) = (google_census_Resource_BasicUnit)value;
+  }
+  return true;
+}
+
+// Validate units field of a Resource proto.
+static bool validate_units(pb_istream_t *stream, const pb_field_t *field,
+                           void **arg) {
+  resource *vresource = (resource *)(*arg);
+  switch (field->tag) {
+    case google_census_Resource_MeasurementUnit_numerator_tag:
+      return validate_units_helper(stream, &vresource->n_numerators,
+                                   &vresource->numerators);
+      break;
+    case google_census_Resource_MeasurementUnit_denominator_tag:
+      return validate_units_helper(stream, &vresource->n_denominators,
+                                   &vresource->denominators);
+      break;
+    default:
+      gpr_log(GPR_ERROR, "Unknown field type.");
+      return false;
+      break;
+  }
+  return true;
+}
+
+// Validate the contents of a Resource proto. `id` is the intended resource id.
+static bool validate_resource_pb(const uint8_t *resource_pb,
+                                 size_t resource_pb_size, size_t id) {
+  GPR_ASSERT(id < n_resources);
+  if (resource_pb == NULL) {
+    return false;
+  }
+  google_census_Resource vresource;
+  vresource.name.funcs.decode = &validate_string;
+  vresource.name.arg = resources[id];
+  vresource.description.funcs.decode = &validate_string;
+  vresource.description.arg = resources[id];
+  vresource.unit.numerator.funcs.decode = &validate_units;
+  vresource.unit.numerator.arg = resources[id];
+  vresource.unit.denominator.funcs.decode = &validate_units;
+  vresource.unit.denominator.arg = resources[id];
+
+  pb_istream_t stream =
+      pb_istream_from_buffer((uint8_t *)resource_pb, resource_pb_size);
+  if (!pb_decode(&stream, google_census_Resource_fields, &vresource)) {
+    return false;
+  }
+  // A Resource must have a name, a unit, with at least one numerator.
+  return (resources[id]->name != NULL && vresource.has_unit &&
+          resources[id]->n_numerators > 0);
+}
+
+// Allocate a blank resource, and return associated ID. Must be called with
+// resource_lock held.
+size_t allocate_resource(void) {
+  // use next_id to optimize expected placement of next new resource.
+  static size_t next_id = 0;
+  size_t id = n_resources;  // resource ID - initialize to invalid value.
+  // Expand resources if needed.
+  if (n_resources == n_defined_resources) {
+    size_t new_n_resources = n_resources ? n_resources * 2 : 2;
+    resource **new_resources = gpr_malloc(new_n_resources * sizeof(resource *));
+    memcpy(new_resources, resources, n_resources * sizeof(resource *));
+    memset(new_resources + n_resources, 0,
+           (new_n_resources - n_resources) * sizeof(resource *));
+    gpr_free(resources);
+    resources = new_resources;
+    n_resources = new_n_resources;
+    id = n_defined_resources;
+  } else {
+    GPR_ASSERT(n_defined_resources < n_resources);
+    // Find a free id.
+    for (size_t base = 0; base < n_resources; base++) {
+      id = (next_id + base) % n_resources;
+      if (resources[id] == NULL) break;
+    }
+  }
+  GPR_ASSERT(id < n_resources && resources[id] == NULL);
+  resources[id] = gpr_malloc(sizeof(resource));
+  memset(resources[id], 0, sizeof(resource));
+  n_defined_resources++;
+  next_id = (id + 1) % n_resources;
+  return id;
+}
+
+int32_t census_define_resource(const uint8_t *resource_pb,
+                               size_t resource_pb_size) {
+  if (resource_pb == NULL) {
+    return -1;
+  }
+  gpr_mu_lock(&resource_lock);
+  size_t id = allocate_resource();
+  // Validate pb, extract name.
+  if (!validate_resource_pb(resource_pb, resource_pb_size, id)) {
+    delete_resource_locked(id);
+    gpr_mu_unlock(&resource_lock);
+    return -1;
+  }
+  gpr_mu_unlock(&resource_lock);
+  return (int32_t)id;
+}
+
+void census_delete_resource(int32_t rid) {
+  gpr_mu_lock(&resource_lock);
+  if (rid >= 0 && (size_t)rid < n_resources && resources[rid] != NULL) {
+    delete_resource_locked((size_t)rid);
+  }
+  gpr_mu_unlock(&resource_lock);
+}
+
+int32_t census_resource_id(const char *name) {
+  gpr_mu_lock(&resource_lock);
+  for (int32_t id = 0; (size_t)id < n_resources; id++) {
+    if (resources[id] != NULL && strcmp(resources[id]->name, name) == 0) {
+      gpr_mu_unlock(&resource_lock);
+      return id;
+    }
+  }
+  gpr_mu_unlock(&resource_lock);
+  return -1;
+}
+
+int32_t define_resource(const resource *base) {
+  GPR_ASSERT(base != NULL && base->name != NULL && base->n_numerators > 0 &&
+             base->numerators != NULL);
+  gpr_mu_lock(&resource_lock);
+  size_t id = allocate_resource();
+  size_t len = strlen(base->name) + 1;
+  resources[id]->name = gpr_malloc(len);
+  memcpy(resources[id]->name, base->name, len);
+  if (base->description) {
+    len = strlen(base->description) + 1;
+    resources[id]->description = gpr_malloc(len);
+    memcpy(resources[id]->description, base->description, len);
+  }
+  resources[id]->prefix = base->prefix;
+  resources[id]->n_numerators = base->n_numerators;
+  len = (size_t)base->n_numerators * sizeof(*base->numerators);
+  resources[id]->numerators = gpr_malloc(len);
+  memcpy(resources[id]->numerators, base->numerators, len);
+  resources[id]->n_denominators = base->n_denominators;
+  if (base->n_denominators != 0) {
+    len = (size_t)base->n_denominators * sizeof(*base->denominators);
+    resources[id]->denominators = gpr_malloc(len);
+    memcpy(resources[id]->denominators, base->denominators, len);
+  }
+  gpr_mu_unlock(&resource_lock);
+  return (int32_t)id;
+}
diff --git a/src/core/ext/census/resource.h b/src/core/ext/census/resource.h
new file mode 100644
index 0000000..591bff0
--- /dev/null
+++ b/src/core/ext/census/resource.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.
+ *
+ */
+
+/* Census-internal resource definition and manipluation functions. */
+#ifndef GRPC_CORE_EXT_CENSUS_RESOURCE_H
+#define GRPC_CORE_EXT_CENSUS_RESOURCE_H
+
+#include <grpc/grpc.h>
+#include "src/core/ext/census/gen/census.pb.h"
+
+/* Internal representation of a resource. */
+typedef struct {
+  char *name;
+  char *description;
+  int32_t prefix;
+  int n_numerators;
+  google_census_Resource_BasicUnit *numerators;
+  int n_denominators;
+  google_census_Resource_BasicUnit *denominators;
+} resource;
+
+/* Initialize and shutdown the resources subsystem. */
+void initialize_resources(void);
+void shutdown_resources(void);
+
+/* Add a new resource, given a proposed resource structure. Returns the
+   resource ID, or -ve on failure.
+   TODO(aveitch): this function exists to support addition of the base
+   resources. It should be removed when we have the ability to add resources
+   from configuration files. */
+int32_t define_resource(const resource *base);
+
+#endif /* GRPC_CORE_EXT_CENSUS_RESOURCE_H */
diff --git a/src/core/ext/client_config/channel_connectivity.c b/src/core/ext/client_config/channel_connectivity.c
index c1220e3..ce3c13a 100644
--- a/src/core/ext/client_config/channel_connectivity.c
+++ b/src/core/ext/client_config/channel_connectivity.c
@@ -59,7 +59,7 @@
   }
   gpr_log(GPR_ERROR,
           "grpc_channel_check_connectivity_state called on something that is "
-          "not a (u)client channel, but '%s'",
+          "not a client channel, but '%s'",
           client_channel_elem->filter->name);
   grpc_exec_ctx_finish(&exec_ctx);
   return GRPC_CHANNEL_SHUTDOWN;
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index a096435..2c0c4ab 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -436,15 +436,17 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem,
                                    args->call_stack);
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats,
+                              const grpc_call_final_info *final_info,
                               void *and_free_memory) {
   grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
   gpr_free(and_free_memory);
diff --git a/src/core/ext/client_config/lb_policy.h b/src/core/ext/client_config/lb_policy.h
index 3cfd041..a2f5446 100644
--- a/src/core/ext/client_config/lb_policy.h
+++ b/src/core/ext/client_config/lb_policy.h
@@ -73,7 +73,7 @@
   void (*ping_one)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
                    grpc_closure *closure);
 
-  /** try to enter a READY connectivity state */
+  /** Try to enter a READY connectivity state */
   void (*exit_idle)(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
 
   /** check the current connectivity of the lb_policy */
@@ -82,7 +82,9 @@
       grpc_error **connectivity_error);
 
   /** call notify when the connectivity state of a channel changes from *state.
-      Updates *state with the new state of the policy */
+      Updates *state with the new state of the policy. Calling with a NULL \a
+      state cancels the subscription.
+      */
   void (*notify_on_state_change)(grpc_exec_ctx *exec_ctx,
                                  grpc_lb_policy *policy,
                                  grpc_connectivity_state *state,
@@ -125,7 +127,7 @@
 /** Given initial metadata in \a initial_metadata, find an appropriate
     target for this rpc, and 'return' it by calling \a on_complete after setting
     \a target.
-    Picking can be asynchronous. Any IO should be done under \a pollset. */
+    Picking can be asynchronous. Any IO should be done under \a pollent. */
 int grpc_lb_policy_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
                         grpc_polling_entity *pollent,
                         grpc_metadata_batch *initial_metadata,
@@ -147,8 +149,11 @@
                                  uint32_t initial_metadata_flags_mask,
                                  uint32_t initial_metadata_flags_eq);
 
+/** Try to enter a READY connectivity state */
 void grpc_lb_policy_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy);
 
+/* Call notify when the connectivity state of a channel changes from \a *state.
+ * Updates \a *state with the new state of the policy */
 void grpc_lb_policy_notify_on_state_change(grpc_exec_ctx *exec_ctx,
                                            grpc_lb_policy *policy,
                                            grpc_connectivity_state *state,
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index d089cd4..df35904 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -702,19 +702,26 @@
   return GET_CONNECTED_SUBCHANNEL(c, acq);
 }
 
-grpc_subchannel_call *grpc_connected_subchannel_create_call(
+grpc_error *grpc_connected_subchannel_create_call(
     grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con,
-    grpc_polling_entity *pollent) {
+    grpc_polling_entity *pollent, grpc_subchannel_call **call) {
   grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con);
-  grpc_subchannel_call *call =
-      gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
-  grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call);
-  call->connection = con;
+  *call = gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
+  grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
+  (*call)->connection = con;  // Ref is added below.
+  grpc_error *error =
+      grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, *call,
+                           NULL, NULL, callstk);
+  if (error != GRPC_ERROR_NONE) {
+    const char *error_string = grpc_error_string(error);
+    gpr_log(GPR_ERROR, "error: %s", error_string);
+    grpc_error_free_string(error_string);
+    gpr_free(*call);
+    return error;
+  }
   GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
-  grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call,
-                       NULL, NULL, callstk);
   grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, pollent);
-  return call;
+  return GRPC_ERROR_NONE;
 }
 
 grpc_call_stack *grpc_subchannel_call_get_call_stack(
diff --git a/src/core/ext/client_config/subchannel.h b/src/core/ext/client_config/subchannel.h
index b6d39f5..ae1d96e 100644
--- a/src/core/ext/client_config/subchannel.h
+++ b/src/core/ext/client_config/subchannel.h
@@ -108,9 +108,9 @@
                                     GRPC_SUBCHANNEL_REF_EXTRA_ARGS);
 
 /** construct a subchannel call */
-grpc_subchannel_call *grpc_connected_subchannel_create_call(
+grpc_error *grpc_connected_subchannel_create_call(
     grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *connected_subchannel,
-    grpc_polling_entity *pollent);
+    grpc_polling_entity *pollent, grpc_subchannel_call **subchannel_call);
 
 /** process a transport level op */
 void grpc_connected_subchannel_process_transport_op(
diff --git a/src/core/ext/client_config/subchannel_call_holder.c b/src/core/ext/client_config/subchannel_call_holder.c
index b96a0ad..be6d054 100644
--- a/src/core/ext/client_config/subchannel_call_holder.c
+++ b/src/core/ext/client_config/subchannel_call_holder.c
@@ -84,6 +84,11 @@
   gpr_free(holder->waiting_ops);
 }
 
+// The logic here is fairly complicated, due to (a) the fact that we
+// need to handle the case where we receive the send op before the
+// initial metadata op, and (b) the need for efficiency, especially in
+// the streaming case.
+// TODO(ctiller): Explain this more thoroughly.
 void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
                                             grpc_subchannel_call_holder *holder,
                                             grpc_transport_stream_op *op) {
@@ -121,7 +126,8 @@
   }
   /* if this is a cancellation, then we can raise our cancelled flag */
   if (op->cancel_error != GRPC_ERROR_NONE) {
-    if (!gpr_atm_rel_cas(&holder->subchannel_call, 0, 1)) {
+    if (!gpr_atm_rel_cas(&holder->subchannel_call, 0,
+                         (gpr_atm)(uintptr_t)CANCELLED_CALL)) {
       goto retry;
     } else {
       switch (holder->creation_phase) {
@@ -158,10 +164,17 @@
   /* if we've got a subchannel, then let's ask it to create a call */
   if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
       holder->connected_subchannel != NULL) {
-    gpr_atm_rel_store(
-        &holder->subchannel_call,
-        (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
-            exec_ctx, holder->connected_subchannel, holder->pollent));
+    grpc_subchannel_call *subchannel_call = NULL;
+    grpc_error *error = grpc_connected_subchannel_create_call(
+        exec_ctx, holder->connected_subchannel, holder->pollent,
+        &subchannel_call);
+    if (error != GRPC_ERROR_NONE) {
+      subchannel_call = CANCELLED_CALL;
+      fail_locked(exec_ctx, holder, GRPC_ERROR_REF(error));
+      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+    }
+    gpr_atm_rel_store(&holder->subchannel_call,
+                      (gpr_atm)(uintptr_t)subchannel_call);
     retry_waiting_locked(exec_ctx, holder);
     goto retry;
   }
@@ -189,10 +202,17 @@
                 GRPC_ERROR_CREATE_REFERENCING(
                     "Cancelled before creating subchannel", &error, 1));
   } else {
-    gpr_atm_rel_store(
-        &holder->subchannel_call,
-        (gpr_atm)(uintptr_t)grpc_connected_subchannel_create_call(
-            exec_ctx, holder->connected_subchannel, holder->pollent));
+    grpc_subchannel_call *subchannel_call = NULL;
+    grpc_error *new_error = grpc_connected_subchannel_create_call(
+        exec_ctx, holder->connected_subchannel, holder->pollent,
+        &subchannel_call);
+    if (new_error != GRPC_ERROR_NONE) {
+      new_error = grpc_error_add_child(new_error, error);
+      subchannel_call = CANCELLED_CALL;
+      fail_locked(exec_ctx, holder, new_error);
+    }
+    gpr_atm_rel_store(&holder->subchannel_call,
+                      (gpr_atm)(uintptr_t)subchannel_call);
     retry_waiting_locked(exec_ctx, holder);
   }
   gpr_mu_unlock(&holder->mu);
diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c
new file mode 100644
index 0000000..af913d8
--- /dev/null
+++ b/src/core/ext/lb_policy/grpclb/grpclb.c
@@ -0,0 +1,1042 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/** Implementation of the gRPC LB policy.
+ *
+ * This policy takes as input a set of resolved addresses {a1..an} for which the
+ * LB set was set (it's the resolver's responsibility to ensure this). That is
+ * to say, {a1..an} represent a collection of LB servers.
+ *
+ * An internal channel (\a glb_lb_policy.lb_channel) is created over {a1..an}.
+ * This channel behaves just like a regular channel. In particular, the
+ * constructed URI over the addresses a1..an will use the default pick first
+ * policy to select from this list of LB server backends.
+ *
+ * The first time the policy gets a request for a pick, a ping, or to exit the
+ * idle state, \a query_for_backends() is called. It creates an instance of \a
+ * lb_client_data, an internal struct meant to contain the data associated with
+ * the internal communication with the LB server. This instance is created via
+ * \a lb_client_data_create(). There, the call over lb_channel to pick-first
+ * from {a1..an} is created, the \a LoadBalancingRequest message is assembled
+ * and all necessary callbacks for the progress of the internal call configured.
+ *
+ * Back in \a query_for_backends(), the internal *streaming* call to the LB
+ * server (whichever address from {a1..an} pick-first chose) is kicked off.
+ * It'll progress over the callbacks configured in \a lb_client_data_create()
+ * (see the field docstrings of \a lb_client_data for more details).
+ *
+ * If the call fails with UNIMPLEMENTED, the original call will also fail.
+ * There's a misconfiguration somewhere: at least one of {a1..an} isn't a LB
+ * server, which contradicts the LB bit being set. If the internal call times
+ * out, the usual behavior of pick-first applies, continuing to pick from the
+ * list {a1..an}.
+ *
+ * Upon sucesss, a \a LoadBalancingResponse is expected in \a res_recv_cb. An
+ * invalid one results in the termination of the streaming call. A new streaming
+ * call should be created if possible, failing the original call otherwise.
+ * For a valid \a LoadBalancingResponse, the server list of actual backends is
+ * extracted. A Round Robin policy will be created from this list. There are two
+ * possible scenarios:
+ *
+ * 1. This is the first server list received. There was no previous instance of
+ *    the Round Robin policy. \a rr_handover() will instantiate the RR policy
+ *    and perform all the pending operations over it.
+ * 2. There's already a RR policy instance active. We need to introduce the new
+ *    one build from the new serverlist, but taking care not to disrupt the
+ *    operations in progress over the old RR instance. This is done by
+ *    decreasing the reference count on the old policy. The moment no more
+ *    references are held on the old RR policy, it'll be destroyed and \a
+ *    rr_connectivity_changed notified with a \a GRPC_CHANNEL_SHUTDOWN state.
+ *    At this point we can transition to a new RR instance safely, which is done
+ *    once again via \a rr_handover().
+ *
+ *
+ * Once a RR policy instance is in place (and getting updated as described),
+ * calls to for a pick, a ping or a cancellation will be serviced right away by
+ * forwarding them to the RR instance. Any time there's no RR policy available
+ * (ie, right after the creation of the gRPCLB policy, if an empty serverlist
+ * is received, etc), pick/ping requests are added to a list of pending
+ * picks/pings to be flushed and serviced as part of \a rr_handover() the moment
+ * the RR policy instance becomes available.
+ *
+ * \see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md for the
+ * high level design and details. */
+
+/* TODO(dgq):
+ * - Implement LB service forwarding (point 2c. in the doc's diagram).
+ */
+
+#include <string.h>
+
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/string_util.h>
+
+#include "src/core/ext/client_config/client_channel_factory.h"
+#include "src/core/ext/client_config/lb_policy_registry.h"
+#include "src/core/ext/client_config/parse_address.h"
+#include "src/core/ext/lb_policy/grpclb/grpclb.h"
+#include "src/core/ext/lb_policy/grpclb/load_balancer_api.h"
+#include "src/core/lib/iomgr/sockaddr_utils.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/channel.h"
+
+int grpc_lb_glb_trace = 0;
+
+typedef struct wrapped_rr_closure_arg {
+  /* the original closure. Usually a on_complete/notify cb for pick() and ping()
+   * calls against the internal RR instance, respectively. */
+  grpc_closure *wrapped_closure;
+
+  /* The RR instance related to the closure */
+  grpc_lb_policy *rr_policy;
+
+  /* when not NULL, represents a pending_{pick,ping} node to be freed upon
+   * closure execution */
+  void *owning_pending_node; /* to be freed if not NULL */
+} wrapped_rr_closure_arg;
+
+/* The \a on_complete closure passed as part of the pick requires keeping a
+ * reference to its associated round robin instance. We wrap this closure in
+ * order to unref the round robin instance upon its invocation */
+static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
+                               grpc_error *error) {
+  wrapped_rr_closure_arg *wc_arg = arg;
+  if (wc_arg->rr_policy != NULL) {
+    if (grpc_lb_glb_trace) {
+      gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")",
+              (intptr_t)wc_arg->rr_policy);
+    }
+    GRPC_LB_POLICY_UNREF(exec_ctx, wc_arg->rr_policy, "wrapped_rr_closure");
+  }
+  GPR_ASSERT(wc_arg->wrapped_closure != NULL);
+  grpc_exec_ctx_sched(exec_ctx, wc_arg->wrapped_closure, error, NULL);
+  gpr_free(wc_arg->owning_pending_node);
+}
+
+/* Linked list of pending pick requests. It stores all information needed to
+ * eventually call (Round Robin's) pick() on them. They mainly stay pending
+ * waiting for the RR policy to be created/updated.
+ *
+ * One particularity is the wrapping of the user-provided \a on_complete closure
+ * (in \a wrapped_on_complete and \a wrapped_on_complete_arg). This is needed in
+ * order to correctly unref the RR policy instance upon completion of the pick.
+ * See \a wrapped_rr_closure for details. */
+typedef struct pending_pick {
+  struct pending_pick *next;
+
+  /* polling entity for the pick()'s async notification */
+  grpc_polling_entity *pollent;
+
+  /* the initial metadata for the pick. See grpc_lb_policy_pick() */
+  grpc_metadata_batch *initial_metadata;
+
+  /* bitmask passed to pick() and used for selective cancelling. See
+   * grpc_lb_policy_cancel_picks() */
+  uint32_t initial_metadata_flags;
+
+  /* output argument where to store the pick()ed connected subchannel, or NULL
+   * upon error. */
+  grpc_connected_subchannel **target;
+
+  /* a closure wrapping the original on_complete one to be invoked once the
+   * pick() has completed (regardless of success) */
+  grpc_closure wrapped_on_complete;
+
+  /* args for wrapped_on_complete */
+  wrapped_rr_closure_arg wrapped_on_complete_arg;
+} pending_pick;
+
+static void add_pending_pick(pending_pick **root, grpc_polling_entity *pollent,
+                             grpc_metadata_batch *initial_metadata,
+                             uint32_t initial_metadata_flags,
+                             grpc_connected_subchannel **target,
+                             grpc_closure *on_complete) {
+  pending_pick *pp = gpr_malloc(sizeof(*pp));
+  memset(pp, 0, sizeof(pending_pick));
+  memset(&pp->wrapped_on_complete_arg, 0, sizeof(wrapped_rr_closure_arg));
+  pp->next = *root;
+  pp->pollent = pollent;
+  pp->target = target;
+  pp->initial_metadata = initial_metadata;
+  pp->initial_metadata_flags = initial_metadata_flags;
+  pp->wrapped_on_complete_arg.wrapped_closure = on_complete;
+  grpc_closure_init(&pp->wrapped_on_complete, wrapped_rr_closure,
+                    &pp->wrapped_on_complete_arg);
+  *root = pp;
+}
+
+/* Same as the \a pending_pick struct but for ping operations */
+typedef struct pending_ping {
+  struct pending_ping *next;
+
+  /* a closure wrapping the original on_complete one to be invoked once the
+   * ping() has completed (regardless of success) */
+  grpc_closure wrapped_notify;
+
+  /* args for wrapped_notify */
+  wrapped_rr_closure_arg wrapped_notify_arg;
+} pending_ping;
+
+static void add_pending_ping(pending_ping **root, grpc_closure *notify) {
+  pending_ping *pping = gpr_malloc(sizeof(*pping));
+  memset(pping, 0, sizeof(pending_ping));
+  memset(&pping->wrapped_notify_arg, 0, sizeof(wrapped_rr_closure_arg));
+  pping->next = *root;
+  grpc_closure_init(&pping->wrapped_notify, wrapped_rr_closure,
+                    &pping->wrapped_notify_arg);
+  pping->wrapped_notify_arg.wrapped_closure = notify;
+  *root = pping;
+}
+
+/*
+ * glb_lb_policy
+ */
+typedef struct rr_connectivity_data rr_connectivity_data;
+struct lb_client_data;
+static const grpc_lb_policy_vtable glb_lb_policy_vtable;
+typedef struct glb_lb_policy {
+  /** base policy: must be first */
+  grpc_lb_policy base;
+
+  /** mutex protecting remaining members */
+  gpr_mu mu;
+
+  grpc_client_channel_factory *cc_factory;
+
+  /** for communicating with the LB server */
+  grpc_channel *lb_channel;
+
+  /** the RR policy to use of the backend servers returned by the LB server */
+  grpc_lb_policy *rr_policy;
+
+  bool started_picking;
+
+  /** our connectivity state tracker */
+  grpc_connectivity_state_tracker state_tracker;
+
+  /** stores the deserialized response from the LB. May be NULL until one such
+   * response has arrived. */
+  grpc_grpclb_serverlist *serverlist;
+
+  /** list of picks that are waiting on RR's policy connectivity */
+  pending_pick *pending_picks;
+
+  /** list of pings that are waiting on RR's policy connectivity */
+  pending_ping *pending_pings;
+
+  /** client data associated with the LB server communication */
+  struct lb_client_data *lb_client;
+
+  /** for tracking of the RR connectivity */
+  rr_connectivity_data *rr_connectivity;
+
+  /* a wrapped (see \a wrapped_rr_closure) on-complete closure for readily
+   * available RR picks */
+  grpc_closure wrapped_on_complete;
+
+  /* arguments for the wrapped_on_complete closure */
+  wrapped_rr_closure_arg wc_arg;
+} glb_lb_policy;
+
+/* Keeps track and reacts to changes in connectivity of the RR instance */
+struct rr_connectivity_data {
+  grpc_closure on_change;
+  grpc_connectivity_state state;
+  glb_lb_policy *glb_policy;
+};
+
+static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx,
+                                 const grpc_grpclb_serverlist *serverlist,
+                                 glb_lb_policy *glb_policy) {
+  /* TODO(dgq): support mixed ip version */
+  GPR_ASSERT(serverlist != NULL && serverlist->num_servers > 0);
+  char **host_ports = gpr_malloc(sizeof(char *) * serverlist->num_servers);
+  for (size_t i = 0; i < serverlist->num_servers; ++i) {
+    gpr_join_host_port(&host_ports[i], serverlist->servers[i]->ip_address,
+                       serverlist->servers[i]->port);
+  }
+
+  size_t uri_path_len;
+  char *concat_ipports = gpr_strjoin_sep(
+      (const char **)host_ports, serverlist->num_servers, ",", &uri_path_len);
+
+  grpc_lb_policy_args args;
+  args.client_channel_factory = glb_policy->cc_factory;
+  args.addresses = gpr_malloc(sizeof(grpc_resolved_addresses));
+  args.addresses->naddrs = serverlist->num_servers;
+  args.addresses->addrs =
+      gpr_malloc(sizeof(grpc_resolved_address) * args.addresses->naddrs);
+  size_t out_addrs_idx = 0;
+  for (size_t i = 0; i < serverlist->num_servers; ++i) {
+    grpc_uri uri;
+    struct sockaddr_storage sa;
+    size_t sa_len;
+    uri.path = host_ports[i];
+    if (parse_ipv4(&uri, &sa, &sa_len)) { /* TODO(dgq): add support for ipv6 */
+      memcpy(args.addresses->addrs[out_addrs_idx].addr, &sa, sa_len);
+      args.addresses->addrs[out_addrs_idx].len = sa_len;
+      ++out_addrs_idx;
+    } else {
+      gpr_log(GPR_ERROR, "Invalid LB service address '%s', ignoring.",
+              host_ports[i]);
+    }
+  }
+
+  grpc_lb_policy *rr = grpc_lb_policy_create(exec_ctx, "round_robin", &args);
+
+  gpr_free(concat_ipports);
+  for (size_t i = 0; i < serverlist->num_servers; i++) {
+    gpr_free(host_ports[i]);
+  }
+  gpr_free(host_ports);
+  gpr_free(args.addresses->addrs);
+  gpr_free(args.addresses);
+  return rr;
+}
+
+static void rr_handover(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy,
+                        grpc_error *error) {
+  GRPC_ERROR_REF(error);
+  glb_policy->rr_policy =
+      create_rr(exec_ctx, glb_policy->serverlist, glb_policy);
+
+  if (grpc_lb_glb_trace) {
+    gpr_log(GPR_INFO, "Created RR policy (0x%" PRIxPTR ")",
+            (intptr_t)glb_policy->rr_policy);
+  }
+  GPR_ASSERT(glb_policy->rr_policy != NULL);
+  glb_policy->rr_connectivity->state = grpc_lb_policy_check_connectivity(
+      exec_ctx, glb_policy->rr_policy, &error);
+  grpc_lb_policy_notify_on_state_change(
+      exec_ctx, glb_policy->rr_policy, &glb_policy->rr_connectivity->state,
+      &glb_policy->rr_connectivity->on_change);
+  grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
+                              glb_policy->rr_connectivity->state, error,
+                              "rr_handover");
+  grpc_lb_policy_exit_idle(exec_ctx, glb_policy->rr_policy);
+
+  /* flush pending ops */
+  pending_pick *pp;
+  while ((pp = glb_policy->pending_picks)) {
+    glb_policy->pending_picks = pp->next;
+    GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_pick");
+    pp->wrapped_on_complete_arg.rr_policy = glb_policy->rr_policy;
+    if (grpc_lb_glb_trace) {
+      gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "",
+              (intptr_t)glb_policy->rr_policy);
+    }
+    grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, pp->pollent,
+                        pp->initial_metadata, pp->initial_metadata_flags,
+                        pp->target, &pp->wrapped_on_complete);
+    pp->wrapped_on_complete_arg.owning_pending_node = pp;
+  }
+
+  pending_ping *pping;
+  while ((pping = glb_policy->pending_pings)) {
+    glb_policy->pending_pings = pping->next;
+    GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_ping");
+    pping->wrapped_notify_arg.rr_policy = glb_policy->rr_policy;
+    if (grpc_lb_glb_trace) {
+      gpr_log(GPR_INFO, "Pending ping about to PING from 0x%" PRIxPTR "",
+              (intptr_t)glb_policy->rr_policy);
+    }
+    grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy,
+                            &pping->wrapped_notify);
+    pping->wrapped_notify_arg.owning_pending_node = pping;
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
+                                    grpc_error *error) {
+  rr_connectivity_data *rr_conn_data = arg;
+  glb_lb_policy *glb_policy = rr_conn_data->glb_policy;
+  if (rr_conn_data->state == GRPC_CHANNEL_SHUTDOWN) {
+    if (glb_policy->serverlist != NULL) {
+      /* a RR policy is shutting down but there's a serverlist available ->
+       * perform a handover */
+      rr_handover(exec_ctx, glb_policy, error);
+    } else {
+      /* shutting down and no new serverlist available. Bail out. */
+      gpr_free(rr_conn_data);
+    }
+  } else {
+    if (error == GRPC_ERROR_NONE) {
+      /* RR not shutting down. Mimic the RR's policy state */
+      grpc_connectivity_state_set(exec_ctx, &glb_policy->state_tracker,
+                                  rr_conn_data->state, error,
+                                  "rr_connectivity_changed");
+      /* resubscribe */
+      grpc_lb_policy_notify_on_state_change(exec_ctx, glb_policy->rr_policy,
+                                            &rr_conn_data->state,
+                                            &rr_conn_data->on_change);
+    } else { /* error */
+      gpr_free(rr_conn_data);
+    }
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
+                                  grpc_lb_policy_factory *factory,
+                                  grpc_lb_policy_args *args) {
+  glb_lb_policy *glb_policy = gpr_malloc(sizeof(*glb_policy));
+  memset(glb_policy, 0, sizeof(*glb_policy));
+
+  /* All input addresses in args->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.
+   *
+   * Create a client channel over them to communicate with a LB service */
+  glb_policy->cc_factory = args->client_channel_factory;
+  GPR_ASSERT(glb_policy->cc_factory != NULL);
+  if (args->addresses->naddrs == 0) {
+    return NULL;
+  }
+
+  /* construct a target from the args->addresses, in the form
+   * ipvX://ip1:port1,ip2:port2,...
+   * TODO(dgq): support mixed ip version */
+  char **addr_strs = gpr_malloc(sizeof(char *) * args->addresses->naddrs);
+  addr_strs[0] =
+      grpc_sockaddr_to_uri((const struct sockaddr *)&args->addresses->addrs[0]);
+  for (size_t i = 1; i < args->addresses->naddrs; i++) {
+    GPR_ASSERT(grpc_sockaddr_to_string(
+                   &addr_strs[i],
+                   (const struct sockaddr *)&args->addresses->addrs[i],
+                   true) == 0);
+  }
+  size_t uri_path_len;
+  char *target_uri_str = gpr_strjoin_sep(
+      (const char **)addr_strs, args->addresses->naddrs, ",", &uri_path_len);
+
+  /* will pick using pick_first */
+  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, NULL);
+
+  gpr_free(target_uri_str);
+  for (size_t i = 0; i < args->addresses->naddrs; i++) {
+    gpr_free(addr_strs[i]);
+  }
+  gpr_free(addr_strs);
+
+  if (glb_policy->lb_channel == NULL) {
+    gpr_free(glb_policy);
+    return NULL;
+  }
+
+  rr_connectivity_data *rr_connectivity =
+      gpr_malloc(sizeof(rr_connectivity_data));
+  memset(rr_connectivity, 0, sizeof(rr_connectivity_data));
+  grpc_closure_init(&rr_connectivity->on_change, rr_connectivity_changed,
+                    rr_connectivity);
+  rr_connectivity->glb_policy = glb_policy;
+  glb_policy->rr_connectivity = rr_connectivity;
+
+  grpc_lb_policy_init(&glb_policy->base, &glb_lb_policy_vtable);
+  gpr_mu_init(&glb_policy->mu);
+  grpc_connectivity_state_init(&glb_policy->state_tracker, GRPC_CHANNEL_IDLE,
+                               "grpclb");
+  return &glb_policy->base;
+}
+
+static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  GPR_ASSERT(glb_policy->pending_picks == NULL);
+  GPR_ASSERT(glb_policy->pending_pings == NULL);
+  grpc_channel_destroy(glb_policy->lb_channel);
+  glb_policy->lb_channel = NULL;
+  grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker);
+  if (glb_policy->serverlist != NULL) {
+    grpc_grpclb_destroy_serverlist(glb_policy->serverlist);
+  }
+  gpr_mu_destroy(&glb_policy->mu);
+  gpr_free(glb_policy);
+}
+
+static void lb_client_data_destroy(struct lb_client_data *lb_client);
+static void glb_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+
+  pending_pick *pp = glb_policy->pending_picks;
+  glb_policy->pending_picks = NULL;
+  pending_ping *pping = glb_policy->pending_pings;
+  glb_policy->pending_pings = NULL;
+  gpr_mu_unlock(&glb_policy->mu);
+
+  while (pp != NULL) {
+    pending_pick *next = pp->next;
+    *pp->target = NULL;
+    grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete, GRPC_ERROR_NONE,
+                        NULL);
+    gpr_free(pp);
+    pp = next;
+  }
+
+  while (pping != NULL) {
+    pending_ping *next = pping->next;
+    grpc_exec_ctx_sched(exec_ctx, &pping->wrapped_notify, GRPC_ERROR_NONE,
+                        NULL);
+    pping = next;
+  }
+
+  if (glb_policy->rr_policy) {
+    /* unsubscribe */
+    grpc_lb_policy_notify_on_state_change(
+        exec_ctx, glb_policy->rr_policy, NULL,
+        &glb_policy->rr_connectivity->on_change);
+    GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->rr_policy, "glb_shutdown");
+  }
+
+  lb_client_data_destroy(glb_policy->lb_client);
+  glb_policy->lb_client = NULL;
+
+  grpc_connectivity_state_set(
+      exec_ctx, &glb_policy->state_tracker, GRPC_CHANNEL_SHUTDOWN,
+      GRPC_ERROR_CREATE("Channel Shutdown"), "glb_shutdown");
+}
+
+static void glb_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                            grpc_connected_subchannel **target) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+  pending_pick *pp = glb_policy->pending_picks;
+  glb_policy->pending_picks = NULL;
+  while (pp != NULL) {
+    pending_pick *next = pp->next;
+    if (pp->target == target) {
+      grpc_polling_entity_del_from_pollset_set(
+          exec_ctx, pp->pollent, glb_policy->base.interested_parties);
+      *target = NULL;
+      grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete,
+                          GRPC_ERROR_CANCELLED, NULL);
+      gpr_free(pp);
+    } else {
+      pp->next = glb_policy->pending_picks;
+      glb_policy->pending_picks = pp;
+    }
+    pp = next;
+  }
+  gpr_mu_unlock(&glb_policy->mu);
+}
+
+static grpc_call *lb_client_data_get_call(struct lb_client_data *lb_client);
+static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                             uint32_t initial_metadata_flags_mask,
+                             uint32_t initial_metadata_flags_eq) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+  if (glb_policy->lb_client != NULL) {
+    /* cancel the call to the load balancer service, if any */
+    grpc_call_cancel(lb_client_data_get_call(glb_policy->lb_client), NULL);
+  }
+  pending_pick *pp = glb_policy->pending_picks;
+  glb_policy->pending_picks = NULL;
+  while (pp != NULL) {
+    pending_pick *next = pp->next;
+    if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
+        initial_metadata_flags_eq) {
+      grpc_polling_entity_del_from_pollset_set(
+          exec_ctx, pp->pollent, glb_policy->base.interested_parties);
+      grpc_exec_ctx_sched(exec_ctx, &pp->wrapped_on_complete,
+                          GRPC_ERROR_CANCELLED, NULL);
+      gpr_free(pp);
+    } else {
+      pp->next = glb_policy->pending_picks;
+      glb_policy->pending_picks = pp;
+    }
+    pp = next;
+  }
+  gpr_mu_unlock(&glb_policy->mu);
+}
+
+static void query_for_backends(grpc_exec_ctx *exec_ctx,
+                               glb_lb_policy *glb_policy);
+static void start_picking(grpc_exec_ctx *exec_ctx, glb_lb_policy *glb_policy) {
+  glb_policy->started_picking = true;
+  query_for_backends(exec_ctx, glb_policy);
+}
+
+static void glb_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+  if (!glb_policy->started_picking) {
+    start_picking(exec_ctx, glb_policy);
+  }
+  gpr_mu_unlock(&glb_policy->mu);
+}
+
+static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                    grpc_polling_entity *pollent,
+                    grpc_metadata_batch *initial_metadata,
+                    uint32_t initial_metadata_flags,
+                    grpc_connected_subchannel **target,
+                    grpc_closure *on_complete) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+  int r;
+
+  if (glb_policy->rr_policy != NULL) {
+    if (grpc_lb_glb_trace) {
+      gpr_log(GPR_INFO, "about to PICK from 0x%" PRIxPTR "",
+              (intptr_t)glb_policy->rr_policy);
+    }
+    GRPC_LB_POLICY_REF(glb_policy->rr_policy, "glb_pick");
+    memset(&glb_policy->wc_arg, 0, sizeof(wrapped_rr_closure_arg));
+    glb_policy->wc_arg.rr_policy = glb_policy->rr_policy;
+    glb_policy->wc_arg.wrapped_closure = on_complete;
+    grpc_closure_init(&glb_policy->wrapped_on_complete, wrapped_rr_closure,
+                      &glb_policy->wc_arg);
+    r = grpc_lb_policy_pick(exec_ctx, glb_policy->rr_policy, pollent,
+                            initial_metadata, initial_metadata_flags, target,
+                            &glb_policy->wrapped_on_complete);
+    if (r != 0) {
+      /* the call to grpc_lb_policy_pick has been sychronous. Unreffing the RR
+       * policy and notify the original callback */
+      glb_policy->wc_arg.wrapped_closure = NULL;
+      if (grpc_lb_glb_trace) {
+        gpr_log(GPR_INFO, "Unreffing RR (0x%" PRIxPTR ")",
+                (intptr_t)glb_policy->wc_arg.rr_policy);
+      }
+      GRPC_LB_POLICY_UNREF(exec_ctx, glb_policy->wc_arg.rr_policy, "glb_pick");
+      grpc_exec_ctx_sched(exec_ctx, glb_policy->wc_arg.wrapped_closure,
+                          GRPC_ERROR_NONE, NULL);
+    }
+  } else {
+    grpc_polling_entity_add_to_pollset_set(exec_ctx, pollent,
+                                           glb_policy->base.interested_parties);
+    add_pending_pick(&glb_policy->pending_picks, pollent, initial_metadata,
+                     initial_metadata_flags, target, on_complete);
+
+    if (!glb_policy->started_picking) {
+      start_picking(exec_ctx, glb_policy);
+    }
+    r = 0;
+  }
+  gpr_mu_unlock(&glb_policy->mu);
+  return r;
+}
+
+static grpc_connectivity_state glb_check_connectivity(
+    grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+    grpc_error **connectivity_error) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  grpc_connectivity_state st;
+  gpr_mu_lock(&glb_policy->mu);
+  st = grpc_connectivity_state_check(&glb_policy->state_tracker,
+                                     connectivity_error);
+  gpr_mu_unlock(&glb_policy->mu);
+  return st;
+}
+
+static void glb_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
+                         grpc_closure *closure) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+  if (glb_policy->rr_policy) {
+    grpc_lb_policy_ping_one(exec_ctx, glb_policy->rr_policy, closure);
+  } else {
+    add_pending_ping(&glb_policy->pending_pings, closure);
+    if (!glb_policy->started_picking) {
+      start_picking(exec_ctx, glb_policy);
+    }
+  }
+  gpr_mu_unlock(&glb_policy->mu);
+}
+
+static void glb_notify_on_state_change(grpc_exec_ctx *exec_ctx,
+                                       grpc_lb_policy *pol,
+                                       grpc_connectivity_state *current,
+                                       grpc_closure *notify) {
+  glb_lb_policy *glb_policy = (glb_lb_policy *)pol;
+  gpr_mu_lock(&glb_policy->mu);
+  grpc_connectivity_state_notify_on_state_change(
+      exec_ctx, &glb_policy->state_tracker, current, notify);
+
+  gpr_mu_unlock(&glb_policy->mu);
+}
+
+/*
+ * lb_client_data
+ *
+ * Used internally for the client call to the LB */
+typedef struct lb_client_data {
+  gpr_mu mu;
+
+  /* called once initial metadata's been sent */
+  grpc_closure md_sent;
+
+  /* called once initial metadata's been received */
+  grpc_closure md_rcvd;
+
+  /* called once the LoadBalanceRequest has been sent to the LB server. See
+   * src/proto/grpc/.../load_balancer.proto */
+  grpc_closure req_sent;
+
+  /* A response from the LB server has been received (or error). Process it */
+  grpc_closure res_rcvd;
+
+  /* After the client has sent a close to the LB server */
+  grpc_closure close_sent;
+
+  /* ... and the status from the LB server has been received */
+  grpc_closure srv_status_rcvd;
+
+  grpc_call *lb_call;    /* streaming call to the LB server, */
+  gpr_timespec deadline; /* for the streaming call to the LB server */
+
+  grpc_metadata_array initial_metadata_recv;  /* initial MD from LB server */
+  grpc_metadata_array trailing_metadata_recv; /* trailing MD from LB server */
+
+  /* what's being sent to the LB server. Note that its value may vary if the LB
+   * server indicates a redirect. */
+  grpc_byte_buffer *request_payload;
+
+  /* response from the LB server, if any. Processed in res_recv_cb() */
+  grpc_byte_buffer *response_payload;
+
+  /* the call's status and status detailset in srv_status_rcvd_cb() */
+  grpc_status_code status;
+  char *status_details;
+  size_t status_details_capacity;
+
+  /* pointer back to the enclosing policy */
+  glb_lb_policy *glb_policy;
+} lb_client_data;
+
+static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
+                          grpc_error *error);
+static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg,
+                               grpc_error *error);
+
+static lb_client_data *lb_client_data_create(glb_lb_policy *glb_policy) {
+  lb_client_data *lb_client = gpr_malloc(sizeof(lb_client_data));
+  memset(lb_client, 0, sizeof(lb_client_data));
+
+  gpr_mu_init(&lb_client->mu);
+  grpc_closure_init(&lb_client->md_sent, md_sent_cb, lb_client);
+
+  grpc_closure_init(&lb_client->md_rcvd, md_recv_cb, lb_client);
+  grpc_closure_init(&lb_client->req_sent, req_sent_cb, lb_client);
+  grpc_closure_init(&lb_client->res_rcvd, res_recv_cb, lb_client);
+  grpc_closure_init(&lb_client->close_sent, close_sent_cb, lb_client);
+  grpc_closure_init(&lb_client->srv_status_rcvd, srv_status_rcvd_cb, lb_client);
+
+  /* TODO(dgq): get the deadline from the client config instead of fabricating
+   * one here. */
+  lb_client->deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                     gpr_time_from_seconds(3, GPR_TIMESPAN));
+
+  /* Note the following LB call progresses every time there's activity in \a
+   * glb_policy->base.interested_parties, which is comprised of the polling
+   * entities passed to glb_pick(). */
+  lb_client->lb_call = grpc_channel_create_pollset_set_call(
+      glb_policy->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
+      glb_policy->base.interested_parties, "/BalanceLoad",
+      NULL, /* FIXME(dgq): which "host" value to use? */
+      lb_client->deadline, NULL);
+
+  grpc_metadata_array_init(&lb_client->initial_metadata_recv);
+  grpc_metadata_array_init(&lb_client->trailing_metadata_recv);
+
+  grpc_grpclb_request *request = grpc_grpclb_request_create(
+      "load.balanced.service.name"); /* FIXME(dgq): get the name of the load
+                                        balanced service from the resolver */
+  gpr_slice request_payload_slice = grpc_grpclb_request_encode(request);
+  lb_client->request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  gpr_slice_unref(request_payload_slice);
+  grpc_grpclb_request_destroy(request);
+
+  lb_client->status_details = NULL;
+  lb_client->status_details_capacity = 0;
+  lb_client->glb_policy = glb_policy;
+  return lb_client;
+}
+
+static void lb_client_data_destroy(lb_client_data *lb_client) {
+  grpc_call_destroy(lb_client->lb_call);
+  grpc_metadata_array_destroy(&lb_client->initial_metadata_recv);
+  grpc_metadata_array_destroy(&lb_client->trailing_metadata_recv);
+
+  grpc_byte_buffer_destroy(lb_client->request_payload);
+
+  gpr_free(lb_client->status_details);
+  gpr_mu_destroy(&lb_client->mu);
+  gpr_free(lb_client);
+}
+static grpc_call *lb_client_data_get_call(lb_client_data *lb_client) {
+  return lb_client->lb_call;
+}
+
+/*
+ * Auxiliary functions and LB client callbacks.
+ */
+static void query_for_backends(grpc_exec_ctx *exec_ctx,
+                               glb_lb_policy *glb_policy) {
+  GPR_ASSERT(glb_policy->lb_channel != NULL);
+
+  glb_policy->lb_client = lb_client_data_create(glb_policy);
+  grpc_call_error call_error;
+  grpc_op ops[1];
+  memset(ops, 0, sizeof(ops));
+  grpc_op *op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  call_error = grpc_call_start_batch_and_execute(
+      exec_ctx, glb_policy->lb_client->lb_call, ops, (size_t)(op - ops),
+      &glb_policy->lb_client->md_sent);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata =
+      &glb_policy->lb_client->trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &glb_policy->lb_client->status;
+  op->data.recv_status_on_client.status_details =
+      &glb_policy->lb_client->status_details;
+  op->data.recv_status_on_client.status_details_capacity =
+      &glb_policy->lb_client->status_details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  call_error = grpc_call_start_batch_and_execute(
+      exec_ctx, glb_policy->lb_client->lb_call, ops, (size_t)(op - ops),
+      &glb_policy->lb_client->srv_status_rcvd);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void md_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  lb_client_data *lb_client = arg;
+  GPR_ASSERT(lb_client->lb_call);
+  grpc_op ops[1];
+  memset(ops, 0, sizeof(ops));
+  grpc_op *op = ops;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &lb_client->initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  grpc_call_error call_error = grpc_call_start_batch_and_execute(
+      exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+      &lb_client->md_rcvd);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void md_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  lb_client_data *lb_client = arg;
+  GPR_ASSERT(lb_client->lb_call);
+  grpc_op ops[1];
+  memset(ops, 0, sizeof(ops));
+  grpc_op *op = ops;
+
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = lb_client->request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  grpc_call_error call_error = grpc_call_start_batch_and_execute(
+      exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+      &lb_client->req_sent);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  lb_client_data *lb_client = arg;
+
+  grpc_op ops[1];
+  memset(ops, 0, sizeof(ops));
+  grpc_op *op = ops;
+
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &lb_client->response_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  grpc_call_error call_error = grpc_call_start_batch_and_execute(
+      exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+      &lb_client->res_rcvd);
+  GPR_ASSERT(GRPC_CALL_OK == call_error);
+}
+
+static void res_recv_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  lb_client_data *lb_client = arg;
+  grpc_op ops[2];
+  memset(ops, 0, sizeof(ops));
+  grpc_op *op = ops;
+  if (lb_client->response_payload != NULL) {
+    /* Received data from the LB server. Look inside
+     * lb_client->response_payload, for
+     * a serverlist. */
+    grpc_byte_buffer_reader bbr;
+    grpc_byte_buffer_reader_init(&bbr, lb_client->response_payload);
+    gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
+    grpc_byte_buffer_destroy(lb_client->response_payload);
+    grpc_grpclb_serverlist *serverlist =
+        grpc_grpclb_response_parse_serverlist(response_slice);
+    if (serverlist != NULL) {
+      gpr_slice_unref(response_slice);
+      if (grpc_lb_glb_trace) {
+        gpr_log(GPR_INFO, "Serverlist with %zu servers received",
+                serverlist->num_servers);
+      }
+
+      /* update serverlist */
+      if (serverlist->num_servers > 0) {
+        if (grpc_grpclb_serverlist_equals(lb_client->glb_policy->serverlist,
+                                          serverlist)) {
+          if (grpc_lb_glb_trace) {
+            gpr_log(GPR_INFO,
+                    "Incoming server list identical to current, ignoring.");
+          }
+        } else { /* new serverlist */
+          if (lb_client->glb_policy->serverlist != NULL) {
+            /* dispose of the old serverlist */
+            grpc_grpclb_destroy_serverlist(lb_client->glb_policy->serverlist);
+          }
+          /* and update the copy in the glb_lb_policy instance */
+          lb_client->glb_policy->serverlist = serverlist;
+        }
+        if (lb_client->glb_policy->rr_policy == NULL) {
+          /* initial "handover", in this case from a null RR policy, meaning
+           * it'll just create the first RR policy instance */
+          rr_handover(exec_ctx, lb_client->glb_policy, error);
+        } else {
+          /* unref the RR policy, eventually leading to its substitution with a
+           * new one constructed from the received serverlist (see
+           * rr_connectivity_changed) */
+          GRPC_LB_POLICY_UNREF(exec_ctx, lb_client->glb_policy->rr_policy,
+                               "serverlist_received");
+        }
+      } else {
+        if (grpc_lb_glb_trace) {
+          gpr_log(GPR_INFO,
+                  "Received empty server list. Picks will stay pending until a "
+                  "response with > 0 servers is received");
+        }
+      }
+
+      /* keep listening for serverlist updates */
+      op->op = GRPC_OP_RECV_MESSAGE;
+      op->data.recv_message = &lb_client->response_payload;
+      op->flags = 0;
+      op->reserved = NULL;
+      op++;
+      const grpc_call_error call_error = grpc_call_start_batch_and_execute(
+          exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+          &lb_client->res_rcvd); /* loop */
+      GPR_ASSERT(GRPC_CALL_OK == call_error);
+      return;
+    }
+
+    GPR_ASSERT(serverlist == NULL);
+    gpr_log(GPR_ERROR, "Invalid LB response received: '%s'",
+            gpr_dump_slice(response_slice, GPR_DUMP_ASCII));
+    gpr_slice_unref(response_slice);
+
+    /* Disconnect from server returning invalid response. */
+    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    grpc_call_error call_error = grpc_call_start_batch_and_execute(
+        exec_ctx, lb_client->lb_call, ops, (size_t)(op - ops),
+        &lb_client->close_sent);
+    GPR_ASSERT(GRPC_CALL_OK == call_error);
+  }
+  /* empty payload: call cancelled by server. Cleanups happening in
+   * srv_status_rcvd_cb */
+}
+
+static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
+                          grpc_error *error) {
+  if (grpc_lb_glb_trace) {
+    gpr_log(GPR_INFO,
+            "Close from LB client sent. Waiting from server status now");
+  }
+}
+
+static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg,
+                               grpc_error *error) {
+  lb_client_data *lb_client = arg;
+  if (grpc_lb_glb_trace) {
+    gpr_log(GPR_INFO,
+            "status from lb server received. Status = %d, Details = '%s', "
+            "Capaticy "
+            "= %zu",
+            lb_client->status, lb_client->status_details,
+            lb_client->status_details_capacity);
+  }
+  /* TODO(dgq): deal with stream termination properly (fire up another one? fail
+   * the original call?) */
+}
+
+/* Code wiring the policy with the rest of the core */
+static const grpc_lb_policy_vtable glb_lb_policy_vtable = {
+    glb_destroy,     glb_shutdown,           glb_pick,
+    glb_cancel_pick, glb_cancel_picks,       glb_ping_one,
+    glb_exit_idle,   glb_check_connectivity, glb_notify_on_state_change};
+
+static void glb_factory_ref(grpc_lb_policy_factory *factory) {}
+
+static void glb_factory_unref(grpc_lb_policy_factory *factory) {}
+
+static const grpc_lb_policy_factory_vtable glb_factory_vtable = {
+    glb_factory_ref, glb_factory_unref, glb_create, "grpclb"};
+
+static grpc_lb_policy_factory glb_lb_policy_factory = {&glb_factory_vtable};
+
+grpc_lb_policy_factory *grpc_glb_lb_factory_create() {
+  return &glb_lb_policy_factory;
+}
+
+/* Plugin registration */
+void grpc_lb_policy_grpclb_init() {
+  grpc_register_lb_policy(grpc_glb_lb_factory_create());
+  grpc_register_tracer("glb", &grpc_lb_glb_trace);
+}
+
+void grpc_lb_policy_grpclb_shutdown() {}
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/src/core/ext/lb_policy/grpclb/grpclb.h
similarity index 70%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to src/core/ext/lb_policy/grpclb/grpclb.h
index df2324c..83552b4 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/src/core/ext/lb_policy/grpclb/grpclb.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,14 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#ifndef GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H
+#define GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#include "src/core/ext/client_config/lb_policy_factory.h"
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+/** Returns a load balancing factory for the glb policy, which tries to connect
+ * to a load balancing server to decide the next successfully connected
+ * subchannel to pick. */
+grpc_lb_policy_factory *grpc_glb_lb_factory_create();
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
-
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+#endif /* GRPC_CORE_EXT_LB_POLICY_GRPCLB_GRPCLB_H */
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.c b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
index 59b8999..f4720a1 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.c
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.c
@@ -38,9 +38,15 @@
 #include <grpc/support/alloc.h>
 
 typedef struct decode_serverlist_arg {
-  int first_pass;
-  int i;
+  /* The first pass counts the number of servers in the server list. The second
+   * one allocates and decodes. */
+  bool first_pass;
+  /* The decoding callback is invoked once per server in serverlist. Remember
+   * which index of the serverlist are we currently decoding */
+  size_t decoding_idx;
+  /* Populated after the first pass. Number of server in the input serverlist */
   size_t num_servers;
+  /* The decoded serverlist */
   grpc_grpclb_server **servers;
 } decode_serverlist_arg;
 
@@ -48,23 +54,24 @@
 static bool decode_serverlist(pb_istream_t *stream, const pb_field_t *field,
                               void **arg) {
   decode_serverlist_arg *dec_arg = *arg;
-  if (dec_arg->first_pass != 0) { /* first pass */
+  if (dec_arg->first_pass) { /* count how many server do we have */
     grpc_grpclb_server server;
     if (!pb_decode(stream, grpc_lb_v1_Server_fields, &server)) {
       return false;
     }
     dec_arg->num_servers++;
-  } else { /* second pass */
+  } else { /* second pass. Actually decode. */
     grpc_grpclb_server *server = gpr_malloc(sizeof(grpc_grpclb_server));
+    memset(server, 0, sizeof(grpc_grpclb_server));
     GPR_ASSERT(dec_arg->num_servers > 0);
-    if (dec_arg->i == 0) { /* first iteration of second pass */
+    if (dec_arg->decoding_idx == 0) { /* first iteration of second pass */
       dec_arg->servers =
           gpr_malloc(sizeof(grpc_grpclb_server *) * dec_arg->num_servers);
     }
     if (!pb_decode(stream, grpc_lb_v1_Server_fields, server)) {
       return false;
     }
-    dec_arg->servers[dec_arg->i++] = server;
+    dec_arg->servers[dec_arg->decoding_idx++] = server;
   }
 
   return true;
@@ -102,57 +109,59 @@
   gpr_free(request);
 }
 
-grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response) {
-  bool status;
+typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response;
+grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
+    gpr_slice encoded_grpc_grpclb_response) {
   pb_istream_t stream =
-      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
-                             GPR_SLICE_LENGTH(encoded_response));
-  grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
-  memset(res, 0, sizeof(*res));
-  status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, res);
-  if (!status) {
-    grpc_grpclb_response_destroy(res);
+      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_grpc_grpclb_response),
+                             GPR_SLICE_LENGTH(encoded_grpc_grpclb_response));
+  grpc_grpclb_response res;
+  memset(&res, 0, sizeof(grpc_grpclb_response));
+  if (!pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res)) {
     return NULL;
   }
-  return res;
+  grpc_grpclb_initial_response *initial_res =
+      gpr_malloc(sizeof(grpc_grpclb_initial_response));
+  memcpy(initial_res, &res.initial_response,
+         sizeof(grpc_grpclb_initial_response));
+
+  return initial_res;
 }
 
 grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
-    gpr_slice encoded_response) {
+    gpr_slice encoded_grpc_grpclb_response) {
   bool status;
   decode_serverlist_arg arg;
   pb_istream_t stream =
-      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_response),
-                             GPR_SLICE_LENGTH(encoded_response));
+      pb_istream_from_buffer(GPR_SLICE_START_PTR(encoded_grpc_grpclb_response),
+                             GPR_SLICE_LENGTH(encoded_grpc_grpclb_response));
   pb_istream_t stream_at_start = stream;
-  grpc_grpclb_response *res = gpr_malloc(sizeof(grpc_grpclb_response));
-  memset(res, 0, sizeof(*res));
+  grpc_grpclb_response res;
+  memset(&res, 0, sizeof(grpc_grpclb_response));
   memset(&arg, 0, sizeof(decode_serverlist_arg));
 
-  res->server_list.servers.funcs.decode = decode_serverlist;
-  res->server_list.servers.arg = &arg;
-  arg.first_pass = 1;
-  status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, res);
+  res.server_list.servers.funcs.decode = decode_serverlist;
+  res.server_list.servers.arg = &arg;
+  arg.first_pass = true;
+  status = pb_decode(&stream, grpc_lb_v1_LoadBalanceResponse_fields, &res);
   if (!status) {
-    grpc_grpclb_response_destroy(res);
     return NULL;
   }
 
-  arg.first_pass = 0;
+  arg.first_pass = false;
   status =
-      pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, res);
+      pb_decode(&stream_at_start, grpc_lb_v1_LoadBalanceResponse_fields, &res);
   if (!status) {
-    grpc_grpclb_response_destroy(res);
     return NULL;
   }
 
   grpc_grpclb_serverlist *sl = gpr_malloc(sizeof(grpc_grpclb_serverlist));
+  memset(sl, 0, sizeof(*sl));
   sl->num_servers = arg.num_servers;
   sl->servers = arg.servers;
-  if (res->server_list.has_expiration_interval) {
-    sl->expiration_interval = res->server_list.expiration_interval;
+  if (res.server_list.has_expiration_interval) {
+    sl->expiration_interval = res.server_list.expiration_interval;
   }
-  grpc_grpclb_response_destroy(res);
   return sl;
 }
 
@@ -167,6 +176,72 @@
   gpr_free(serverlist);
 }
 
-void grpc_grpclb_response_destroy(grpc_grpclb_response *response) {
+grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy(
+    const grpc_grpclb_serverlist *sl) {
+  grpc_grpclb_serverlist *copy = gpr_malloc(sizeof(grpc_grpclb_serverlist));
+  memset(copy, 0, sizeof(grpc_grpclb_serverlist));
+  copy->num_servers = sl->num_servers;
+  memcpy(&copy->expiration_interval, &sl->expiration_interval,
+         sizeof(grpc_grpclb_duration));
+  copy->servers = gpr_malloc(sizeof(grpc_grpclb_server *) * sl->num_servers);
+  for (size_t i = 0; i < sl->num_servers; i++) {
+    copy->servers[i] = gpr_malloc(sizeof(grpc_grpclb_server));
+    memcpy(copy->servers[i], sl->servers[i], sizeof(grpc_grpclb_server));
+  }
+  return copy;
+}
+
+bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs,
+                                   const grpc_grpclb_serverlist *rhs) {
+  if ((lhs == NULL) || (rhs == NULL)) {
+    return false;
+  }
+  if (lhs->num_servers != rhs->num_servers) {
+    return false;
+  }
+  if (grpc_grpclb_duration_compare(&lhs->expiration_interval,
+                                   &rhs->expiration_interval) != 0) {
+    return false;
+  }
+  for (size_t i = 0; i < lhs->num_servers; i++) {
+    if (!grpc_grpclb_server_equals(lhs->servers[i], rhs->servers[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs,
+                               const grpc_grpclb_server *rhs) {
+  return memcmp(lhs, rhs, sizeof(grpc_grpclb_server)) == 0;
+}
+
+int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs,
+                                 const grpc_grpclb_duration *rhs) {
+  GPR_ASSERT(lhs && rhs);
+  if (lhs->has_seconds && rhs->has_seconds) {
+    if (lhs->seconds < rhs->seconds) return -1;
+    if (lhs->seconds > rhs->seconds) return 1;
+  } else if (lhs->has_seconds) {
+    return 1;
+  } else if (rhs->has_seconds) {
+    return -1;
+  }
+
+  GPR_ASSERT(lhs->seconds == rhs->seconds);
+  if (lhs->has_nanos && rhs->has_nanos) {
+    if (lhs->nanos < rhs->nanos) return -1;
+    if (lhs->nanos > rhs->nanos) return 1;
+  } else if (lhs->has_nanos) {
+    return 1;
+  } else if (rhs->has_nanos) {
+    return -1;
+  }
+
+  return 0;
+}
+
+void grpc_grpclb_initial_response_destroy(
+    grpc_grpclb_initial_response *response) {
   gpr_free(response);
 }
diff --git a/src/core/ext/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
index 71b5616..9726c87 100644
--- a/src/core/ext/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/lb_policy/grpclb/load_balancer_api.h
@@ -46,7 +46,7 @@
 #define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128
 
 typedef grpc_lb_v1_LoadBalanceRequest grpc_grpclb_request;
-typedef grpc_lb_v1_LoadBalanceResponse grpc_grpclb_response;
+typedef grpc_lb_v1_InitialLoadBalanceResponse grpc_grpclb_initial_response;
 typedef grpc_lb_v1_Server grpc_grpclb_server;
 typedef grpc_lb_v1_Duration grpc_grpclb_duration;
 typedef struct grpc_grpclb_serverlist {
@@ -64,19 +64,37 @@
 /** Destroy \a request */
 void grpc_grpclb_request_destroy(grpc_grpclb_request *request);
 
-/** Parse (ie, decode) the bytes in \a encoded_response as a \a
- * grpc_grpclb_response */
-grpc_grpclb_response *grpc_grpclb_response_parse(gpr_slice encoded_response);
+/** Parse (ie, decode) the bytes in \a encoded_grpc_grpclb_response as a \a
+ * grpc_grpclb_initial_response */
+grpc_grpclb_initial_response *grpc_grpclb_initial_response_parse(
+    gpr_slice encoded_grpc_grpclb_response);
+
+/** Parse the list of servers from an encoded \a grpc_grpclb_response */
+grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
+    gpr_slice encoded_grpc_grpclb_response);
+
+/** Return a copy of \a sl. The caller is responsible for calling \a
+ * grpc_grpclb_destroy_serverlist on the returned copy. */
+grpc_grpclb_serverlist *grpc_grpclb_serverlist_copy(
+    const grpc_grpclb_serverlist *sl);
+
+bool grpc_grpclb_serverlist_equals(const grpc_grpclb_serverlist *lhs,
+                                   const grpc_grpclb_serverlist *rhs);
+
+bool grpc_grpclb_server_equals(const grpc_grpclb_server *lhs,
+                               const grpc_grpclb_server *rhs);
 
 /** Destroy \a serverlist */
 void grpc_grpclb_destroy_serverlist(grpc_grpclb_serverlist *serverlist);
 
-/** Parse the list of servers from an encoded \a grpc_grpclb_response */
-grpc_grpclb_serverlist *grpc_grpclb_response_parse_serverlist(
-    gpr_slice encoded_response);
+/** Compare \a lhs against \a rhs and return 0 if \a lhs and \a rhs are equal,
+ * < 0 if \a lhs represents a duration shorter than \a rhs and > 0 otherwise */
+int grpc_grpclb_duration_compare(const grpc_grpclb_duration *lhs,
+                                 const grpc_grpclb_duration *rhs);
 
-/** Destroy \a response */
-void grpc_grpclb_response_destroy(grpc_grpclb_response *response);
+/** Destroy \a initial_response */
+void grpc_grpclb_initial_response_destroy(
+    grpc_grpclb_initial_response *response);
 
 #ifdef __cplusplus
 }
diff --git a/src/core/ext/load_reporting/load_reporting.c b/src/core/ext/load_reporting/load_reporting.c
index 9e4d326..df1ea0e 100644
--- a/src/core/ext/load_reporting/load_reporting.c
+++ b/src/core/ext/load_reporting/load_reporting.c
@@ -42,42 +42,12 @@
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_init.h"
 
-struct grpc_load_reporting_config {
-  grpc_load_reporting_fn fn;
-  void *user_data;
-};
-
-grpc_load_reporting_config *grpc_load_reporting_config_create(
-    grpc_load_reporting_fn fn, void *user_data) {
-  GPR_ASSERT(fn != NULL);
-  grpc_load_reporting_config *lrc =
-      gpr_malloc(sizeof(grpc_load_reporting_config));
-  lrc->fn = fn;
-  lrc->user_data = user_data;
-  return lrc;
-}
-
-grpc_load_reporting_config *grpc_load_reporting_config_copy(
-    grpc_load_reporting_config *src) {
-  return grpc_load_reporting_config_create(src->fn, src->user_data);
-}
-
-void grpc_load_reporting_config_destroy(grpc_load_reporting_config *lrc) {
-  gpr_free(lrc);
-}
-
-void grpc_load_reporting_config_call(
-    grpc_load_reporting_config *lrc,
-    const grpc_load_reporting_call_data *call_data) {
-  lrc->fn(call_data, lrc->user_data);
-}
-
 static bool is_load_reporting_enabled(const grpc_channel_args *a) {
   if (a == NULL) return false;
   for (size_t i = 0; i < a->num_args; i++) {
     if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_LOAD_REPORTING)) {
-      return a->args[i].type == GRPC_ARG_POINTER &&
-             a->args[i].value.pointer.p != NULL;
+      return a->args[i].type == GRPC_ARG_INTEGER &&
+             a->args[i].value.integer != 0;
     }
   }
   return false;
@@ -94,37 +64,17 @@
   return true;
 }
 
-static void lrd_arg_destroy(void *p) { grpc_load_reporting_config_destroy(p); }
-
-static void *lrd_arg_copy(void *p) {
-  return grpc_load_reporting_config_copy(p);
-}
-
-static int lrd_arg_cmp(void *a, void *b) {
-  grpc_load_reporting_config *lhs = a;
-  grpc_load_reporting_config *rhs = b;
-  return !(lhs->fn == rhs->fn && lhs->user_data == rhs->user_data);
-}
-
-static const grpc_arg_pointer_vtable lrd_ptr_vtable = {
-    lrd_arg_copy, lrd_arg_destroy, lrd_arg_cmp};
-
-grpc_arg grpc_load_reporting_config_create_arg(
-    grpc_load_reporting_config *lrc) {
+grpc_arg grpc_load_reporting_enable_arg() {
   grpc_arg arg;
-  arg.type = GRPC_ARG_POINTER;
+  arg.type = GRPC_ARG_INTEGER;
   arg.key = GRPC_ARG_ENABLE_LOAD_REPORTING;
-  arg.value.pointer.p = lrc;
-  arg.value.pointer.vtable = &lrd_ptr_vtable;
+  arg.value.integer = 1;
   return arg;
 }
 
 /* Plugin registration */
 
 void grpc_load_reporting_plugin_init(void) {
-  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX,
-                                   maybe_add_load_reporting_filter,
-                                   (void *)&grpc_load_reporting_filter);
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
                                    maybe_add_load_reporting_filter,
                                    (void *)&grpc_load_reporting_filter);
diff --git a/src/core/ext/load_reporting/load_reporting.h b/src/core/ext/load_reporting/load_reporting.h
index 316cd89..e37817d 100644
--- a/src/core/ext/load_reporting/load_reporting.h
+++ b/src/core/ext/load_reporting/load_reporting.h
@@ -34,42 +34,47 @@
 #ifndef GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H
 #define GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H
 
-#include "src/core/lib/iomgr/closure.h"
-#include "src/core/lib/surface/call.h"
+#include <grpc/impl/codegen/grpc_types.h>
+#include "src/core/lib/channel/channel_stack.h"
 
-typedef struct grpc_load_reporting_config grpc_load_reporting_config;
+/** Metadata key for initial metadata coming from clients */
+/* TODO(dgq): change to the final value TBD */
+#define GRPC_LOAD_REPORTING_INITIAL_MD_KEY "load-reporting-initial"
 
-/** Call information to be passed to the provided load reporting function upon
- * completion of the call */
+/** Metadata key for trailing metadata from servers */
+/* TODO(dgq): change to the final value TBD */
+#define GRPC_LOAD_REPORTING_TRAILING_MD_KEY "load-reporting-trailing"
+
+/** Identifiers for the invocation point of the users LR callback */
+typedef enum grpc_load_reporting_source {
+  GRPC_LR_POINT_UNKNOWN = 0,
+  GRPC_LR_POINT_CHANNEL_CREATION,
+  GRPC_LR_POINT_CHANNEL_DESTRUCTION,
+  GRPC_LR_POINT_CALL_CREATION,
+  GRPC_LR_POINT_CALL_DESTRUCTION
+} grpc_load_reporting_source;
+
+/** Call information to be passed to the provided LR callback. */
 typedef struct grpc_load_reporting_call_data {
-  const grpc_call_stats *stats;   /**< Stats for the call */
-  const char *trailing_md_string; /**< LR trailing metadata info */
+  const grpc_load_reporting_source source; /**< point of last data update. */
+
+  /** Unique identifier for the channel associated with the data */
+  intptr_t channel_id;
+
+  /** Unique identifier for the call associated with the data. If the call
+   * hasn't been created yet, it'll have a value of zero. */
+  intptr_t call_id;
+
+  /** Only valid when \a source is \a GRPC_LR_POINT_CALL_DESTRUCTION, that is,
+   * once the call has completed */
+  const grpc_call_final_info *final_info;
+
+  const char *initial_md_string;  /**< value string for LR's initial md key */
+  const char *trailing_md_string; /**< value string for LR's trailing md key */
+  const char *method_name;        /**< Corresponds to :path header */
 } grpc_load_reporting_call_data;
 
-/** Custom function to be called by the load reporting filter. */
-typedef void (*grpc_load_reporting_fn)(
-    const grpc_load_reporting_call_data *call_data, void *user_data);
-
-/** Register \a fn as the function to be invoked by the load reporting filter.
- * \a fn will be invoked at the beginning and at the end of the call.
- *
- * For the first invocation, \a fn's first argument
- * (grpc_load_reporting_call_data*) will be NULL. \a user_data is always passed
- * as-is. */
-grpc_load_reporting_config *grpc_load_reporting_config_create(
-    grpc_load_reporting_fn fn, void *user_data);
-
-grpc_load_reporting_config *grpc_load_reporting_config_copy(
-    grpc_load_reporting_config *src);
-
-void grpc_load_reporting_config_destroy(grpc_load_reporting_config *lrc);
-
-/** Invoke the function registered by \a grpc_load_reporting_init. */
-void grpc_load_reporting_config_call(
-    grpc_load_reporting_config *lrc,
-    const grpc_load_reporting_call_data *call_data);
-
 /** Return a \a grpc_arg enabling load reporting */
-grpc_arg grpc_load_reporting_config_create_arg(grpc_load_reporting_config *lrc);
+grpc_arg grpc_load_reporting_enable_arg();
 
 #endif /* GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_H */
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index f372f88..394f0cb 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -31,6 +31,7 @@
  *
  */
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
@@ -42,38 +43,112 @@
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/transport/static_metadata.h"
 
-typedef struct call_data { const char *trailing_md_string; } call_data;
+typedef struct call_data {
+  intptr_t id; /**< an id unique to the call */
+  char *trailing_md_string;
+  char *initial_md_string;
+  const char *service_method;
+
+  /* stores the recv_initial_metadata op's ready closure, which we wrap with our
+   * own (on_initial_md_ready) in order to capture the incoming initial metadata
+   * */
+  grpc_closure *ops_recv_initial_metadata_ready;
+
+  /* to get notified of the availability of the incoming initial metadata. */
+  grpc_closure on_initial_md_ready;
+  grpc_metadata_batch *recv_initial_metadata;
+} call_data;
+
 typedef struct channel_data {
-  gpr_mu mu;
-  grpc_load_reporting_config *lrc;
+  intptr_t id; /**< an id unique to the channel */
 } channel_data;
 
-static void invoke_lr_fn_locked(grpc_load_reporting_config *lrc,
-                                grpc_load_reporting_call_data *lr_call_data) {
-  GPR_TIMER_BEGIN("load_reporting_config_fn", 0);
-  grpc_load_reporting_config_call(lrc, lr_call_data);
-  GPR_TIMER_END("load_reporting_config_fn", 0);
+typedef struct {
+  grpc_call_element *elem;
+  grpc_exec_ctx *exec_ctx;
+} recv_md_filter_args;
+
+static grpc_mdelem *recv_md_filter(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;
+
+  if (md->key == GRPC_MDSTR_PATH) {
+    calld->service_method = grpc_mdstr_as_c_string(md->value);
+  } else if (md->key == GRPC_MDSTR_LOAD_REPORTING_INITIAL) {
+    calld->initial_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
+    return NULL;
+  }
+
+  return md;
+}
+
+static void on_initial_md_ready(grpc_exec_ctx *exec_ctx, void *user_data,
+                                grpc_error *err) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+
+  if (err == GRPC_ERROR_NONE) {
+    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);
+    if (calld->service_method == NULL) {
+      err =
+          grpc_error_add_child(err, GRPC_ERROR_CREATE("Missing :path header"));
+    }
+  } else {
+    GRPC_ERROR_REF(err);
+  }
+  calld->ops_recv_initial_metadata_ready->cb(
+      exec_ctx, calld->ops_recv_initial_metadata_ready->cb_arg, err);
+  GRPC_ERROR_UNREF(err);
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   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);
+
+  /* TODO(dgq): do something with the data
+  channel_data *chand = elem->channel_data;
+  grpc_load_reporting_call_data lr_call_data = {GRPC_LR_POINT_CALL_CREATION,
+                                                (intptr_t)chand->id,
+                                                (intptr_t)calld->id,
+                                                NULL,
+                                                NULL,
+                                                NULL,
+                                                NULL};
+  */
+
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {
-  channel_data *chand = elem->channel_data;
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {
   call_data *calld = elem->call_data;
 
-  grpc_load_reporting_call_data lr_call_data = {stats,
-                                                calld->trailing_md_string};
+  /* TODO(dgq): do something with the data
+  channel_data *chand = elem->channel_data;
+  grpc_load_reporting_call_data lr_call_data = {GRPC_LR_POINT_CALL_DESTRUCTION,
+                                                (intptr_t)chand->id,
+                                                (intptr_t)calld->id,
+                                                final_info,
+                                                calld->initial_md_string,
+                                                calld->trailing_md_string,
+                                                calld->service_method};
+  */
 
-  gpr_mu_lock(&chand->mu);
-  invoke_lr_fn_locked(chand->lrc, &lr_call_data);
-  gpr_mu_unlock(&chand->mu);
+  gpr_free(calld->initial_md_string);
+  gpr_free(calld->trailing_md_string);
 }
 
 /* Constructor for channel_data */
@@ -85,37 +160,40 @@
   channel_data *chand = elem->channel_data;
   memset(chand, 0, sizeof(channel_data));
 
-  gpr_mu_init(&chand->mu);
-  for (size_t i = 0; i < args->channel_args->num_args; i++) {
-    if (0 == strcmp(args->channel_args->args[i].key,
-                    GRPC_ARG_ENABLE_LOAD_REPORTING)) {
-      grpc_load_reporting_config *arg_lrc =
-          args->channel_args->args[i].value.pointer.p;
-      chand->lrc = grpc_load_reporting_config_copy(arg_lrc);
-      GPR_ASSERT(chand->lrc != NULL);
-      break;
-    }
-  }
-  GPR_ASSERT(chand->lrc != NULL); /* arg actually found */
+  chand->id = (intptr_t)args->channel_stack;
 
-  gpr_mu_lock(&chand->mu);
-  invoke_lr_fn_locked(chand->lrc, NULL);
-  gpr_mu_unlock(&chand->mu);
+  /* TODO(dgq): do something with the data
+  grpc_load_reporting_call_data lr_call_data = {GRPC_LR_POINT_CHANNEL_CREATION,
+                                                (intptr_t)chand,
+                                                0,
+                                                NULL,
+                                                NULL,
+                                                NULL,
+                                                NULL};
+                                                */
 }
 
 /* Destructor for channel data */
 static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {
+  /* TODO(dgq): do something with the data
   channel_data *chand = elem->channel_data;
-  gpr_mu_destroy(&chand->mu);
-  grpc_load_reporting_config_destroy(chand->lrc);
+  grpc_load_reporting_call_data lr_call_data = {
+      GRPC_LR_POINT_CHANNEL_DESTRUCTION,
+      (intptr_t)chand->id,
+      0,
+      NULL,
+      NULL,
+      NULL,
+      NULL};
+  */
 }
 
 static grpc_mdelem *lr_trailing_md_filter(void *user_data, grpc_mdelem *md) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
 
-  if (md->key == GRPC_MDSTR_LOAD_REPORTING) {
+  if (md->key == GRPC_MDSTR_LOAD_REPORTING_TRAILING) {
     calld->trailing_md_string = gpr_strdup(grpc_mdstr_as_c_string(md->value));
     return NULL;
   }
@@ -127,8 +205,14 @@
                                          grpc_call_element *elem,
                                          grpc_transport_stream_op *op) {
   GPR_TIMER_BEGIN("lr_start_transport_stream_op", 0);
+  call_data *calld = elem->call_data;
 
-  if (op->send_trailing_metadata) {
+  if (op->recv_initial_metadata) {
+    calld->recv_initial_metadata = op->recv_initial_metadata;
+    /* substitute our callback for the higher callback */
+    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,
                                lr_trailing_md_filter, elem);
   }
diff --git a/src/core/ext/load_reporting/load_reporting_filter.h b/src/core/ext/load_reporting/load_reporting_filter.h
index f69cd6f..160ed32 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.h
+++ b/src/core/ext/load_reporting/load_reporting_filter.h
@@ -34,6 +34,7 @@
 #ifndef GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H
 #define GRPC_CORE_EXT_LOAD_REPORTING_LOAD_REPORTING_FILTER_H
 
+#include "src/core/ext/load_reporting/load_reporting.h"
 #include "src/core/lib/channel/channel_stack.h"
 
 extern const grpc_channel_filter grpc_load_reporting_filter;
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 85f9efb..cbaa75a 100644
--- a/src/core/ext/transport/chttp2/client/insecure/channel_create.c
+++ b/src/core/ext/transport/chttp2/client/insecure/channel_create.c
@@ -45,6 +45,7 @@
 #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/compress_filter.h"
+#include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/channel/http_client_filter.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -63,6 +64,8 @@
   grpc_endpoint *tcp;
 
   grpc_closure connected;
+
+  grpc_handshake_manager *handshake_mgr;
 } connector;
 
 static void connector_ref(grpc_connector *con) {
@@ -74,6 +77,7 @@
   connector *c = (connector *)con;
   if (gpr_unref(&c->refs)) {
     /* c->initial_string_buffer does not need to be destroyed */
+    grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
     gpr_free(c);
   }
 }
@@ -83,9 +87,29 @@
   connector_unref(exec_ctx, arg);
 }
 
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
+                              grpc_channel_args *args,
+                              gpr_slice_buffer *read_buffer, void *user_data,
+                              grpc_error *error) {
+  connector *c = user_data;
+  if (error != GRPC_ERROR_NONE) {
+    grpc_channel_args_destroy(args);
+    gpr_free(read_buffer);
+  } else {
+    c->result->transport =
+        grpc_create_chttp2_transport(exec_ctx, args, endpoint, 1);
+    GPR_ASSERT(c->result->transport);
+    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport,
+                                        read_buffer);
+    c->result->channel_args = args;
+  }
+  grpc_closure *notify = c->notify;
+  c->notify = NULL;
+  grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
+}
+
 static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
   connector *c = arg;
-  grpc_closure *notify;
   grpc_endpoint *tcp = c->tcp;
   if (tcp != NULL) {
     if (!GPR_SLICE_IS_EMPTY(c->args.initial_connect_string)) {
@@ -97,19 +121,17 @@
       connector_ref(arg);
       grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
                           &c->initial_string_sent);
+    } else {
+      grpc_handshake_manager_do_handshake(
+          exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
+          c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
     }
-    c->result->transport =
-        grpc_create_chttp2_transport(exec_ctx, c->args.channel_args, tcp, 1);
-    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
-                                        0);
-    GPR_ASSERT(c->result->transport);
-    c->result->channel_args = grpc_channel_args_copy(c->args.channel_args);
   } else {
     memset(c->result, 0, sizeof(*c->result));
+    grpc_closure *notify = c->notify;
+    c->notify = NULL;
+    grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
   }
-  notify = c->notify;
-  c->notify = NULL;
-  grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
 }
 
 static void connector_shutdown(grpc_exec_ctx *exec_ctx, grpc_connector *con) {}
@@ -171,6 +193,7 @@
   memset(c, 0, sizeof(*c));
   c->base.vtable = &connector_vtable;
   gpr_ref_init(&c->refs, 1);
+  c->handshake_mgr = grpc_handshake_manager_create();
   args->args = final_args;
   s = grpc_subchannel_create(exec_ctx, &c->base, args);
   grpc_connector_unref(exec_ctx, &c->base);
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 ca435c2..b2c5e5b 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
@@ -75,7 +75,7 @@
   grpc_channel *channel = grpc_channel_create(
       &exec_ctx, target, final_args, GRPC_CLIENT_DIRECT_CHANNEL, transport);
   grpc_channel_args_destroy(final_args);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  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 9acacbd..9e2bdd7 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
@@ -44,6 +44,7 @@
 #include "src/core/ext/client_config/resolver_registry.h"
 #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/iomgr/tcp_client.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
@@ -69,6 +70,11 @@
   grpc_endpoint *newly_connecting_endpoint;
 
   grpc_closure connected_closure;
+
+  grpc_handshake_manager *handshake_mgr;
+
+  // TODO(roth): Remove once we eliminate on_secure_handshake_done().
+  grpc_channel_args *tmp_args;
 } connector;
 
 static void connector_ref(grpc_connector *con) {
@@ -80,6 +86,8 @@
   connector *c = (connector *)con;
   if (gpr_unref(&c->refs)) {
     /* c->initial_string_buffer does not need to be destroyed */
+    grpc_channel_args_destroy(c->tmp_args);
+    grpc_handshake_manager_destroy(exec_ctx, c->handshake_mgr);
     gpr_free(c);
   }
 }
@@ -89,7 +97,6 @@
                                      grpc_endpoint *secure_endpoint,
                                      grpc_auth_context *auth_context) {
   connector *c = arg;
-  grpc_closure *notify;
   gpr_mu_lock(&c->mu);
   grpc_error *error = GRPC_ERROR_NONE;
   if (c->connecting_endpoint == NULL) {
@@ -107,28 +114,47 @@
     gpr_mu_unlock(&c->mu);
     c->result->transport = grpc_create_chttp2_transport(
         exec_ctx, c->args.channel_args, secure_endpoint, 1);
-    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL,
-                                        0);
+    grpc_chttp2_transport_start_reading(exec_ctx, c->result->transport, NULL);
     auth_context_arg = grpc_auth_context_to_arg(auth_context);
-    c->result->channel_args = grpc_channel_args_copy_and_add(
-        c->args.channel_args, &auth_context_arg, 1);
+    c->result->channel_args =
+        grpc_channel_args_copy_and_add(c->tmp_args, &auth_context_arg, 1);
   }
-  notify = c->notify;
+  grpc_closure *notify = c->notify;
   c->notify = NULL;
   grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
 }
 
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
+                              grpc_channel_args *args,
+                              gpr_slice_buffer *read_buffer, void *user_data,
+                              grpc_error *error) {
+  connector *c = user_data;
+  c->tmp_args = args;
+  if (error != GRPC_ERROR_NONE) {
+    gpr_free(read_buffer);
+    grpc_closure *notify = c->notify;
+    c->notify = NULL;
+    grpc_exec_ctx_sched(exec_ctx, notify, error, NULL);
+  } else {
+    // TODO(roth, jboeuf): Convert security connector handshaking to use new
+    // handshake API, and then move the code from on_secure_handshake_done()
+    // into this function.
+    grpc_channel_security_connector_do_handshake(
+        exec_ctx, c->security_connector, endpoint, read_buffer,
+        c->args.deadline, on_secure_handshake_done, c);
+  }
+}
+
 static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
                                            grpc_error *error) {
   connector *c = arg;
-  grpc_channel_security_connector_do_handshake(
-      exec_ctx, c->security_connector, c->connecting_endpoint, c->args.deadline,
-      on_secure_handshake_done, c);
+  grpc_handshake_manager_do_handshake(
+      exec_ctx, c->handshake_mgr, c->connecting_endpoint, c->args.channel_args,
+      c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
 }
 
 static void connected(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
   connector *c = arg;
-  grpc_closure *notify;
   grpc_endpoint *tcp = c->newly_connecting_endpoint;
   if (tcp != NULL) {
     gpr_mu_lock(&c->mu);
@@ -144,13 +170,13 @@
       grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
                           &c->initial_string_sent);
     } else {
-      grpc_channel_security_connector_do_handshake(
-          exec_ctx, c->security_connector, tcp, c->args.deadline,
-          on_secure_handshake_done, c);
+      grpc_handshake_manager_do_handshake(
+          exec_ctx, c->handshake_mgr, tcp, c->args.channel_args,
+          c->args.deadline, NULL /* acceptor */, on_handshake_done, c);
     }
   } else {
     memset(c->result, 0, sizeof(*c->result));
-    notify = c->notify;
+    grpc_closure *notify = c->notify;
     c->notify = NULL;
     grpc_exec_ctx_sched(exec_ctx, notify, GRPC_ERROR_REF(error), NULL);
   }
@@ -229,6 +255,7 @@
   memset(c, 0, sizeof(*c));
   c->base.vtable = &connector_vtable;
   c->security_connector = f->security_connector;
+  c->handshake_mgr = grpc_handshake_manager_create();
   gpr_mu_init(&c->mu);
   gpr_ref_init(&c->refs, 1);
   args->args = final_args;
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 e5c9879..f0e0742 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -37,35 +37,76 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
+
 #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/http_server_filter.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/server.h"
 
-static void new_transport(grpc_exec_ctx *exec_ctx, void *server,
-                          grpc_endpoint *tcp, grpc_pollset *accepting_pollset,
-                          grpc_tcp_server_acceptor *acceptor) {
-  /*
-   * Beware that the call to grpc_create_chttp2_transport() has to happen before
-   * grpc_tcp_server_destroy(). This is fine here, but similar code
-   * asynchronously doing a handshake instead of calling grpc_tcp_server_start()
-   * (as in server_secure_chttp2.c) needs to add synchronization to avoid this
-   * case.
-   */
-  grpc_transport *transport = grpc_create_chttp2_transport(
-      exec_ctx, grpc_server_get_channel_args(server), tcp, 0);
-  grpc_server_setup_transport(exec_ctx, server, transport, accepting_pollset,
-                              grpc_server_get_channel_args(server));
-  grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
+typedef struct server_connect_state {
+  grpc_server *server;
+  grpc_pollset *accepting_pollset;
+  grpc_tcp_server_acceptor *acceptor;
+  grpc_handshake_manager *handshake_mgr;
+} server_connect_state;
+
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
+                              grpc_channel_args *args,
+                              gpr_slice_buffer *read_buffer, void *user_data,
+                              grpc_error *error) {
+  server_connect_state *state = user_data;
+  if (error != GRPC_ERROR_NONE) {
+    const char *error_str = grpc_error_string(error);
+    gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
+    grpc_error_free_string(error_str);
+    GRPC_ERROR_UNREF(error);
+    grpc_handshake_manager_shutdown(exec_ctx, state->handshake_mgr);
+    gpr_free(read_buffer);
+  } else {
+    // Beware that the call to grpc_create_chttp2_transport() has to happen
+    // before grpc_tcp_server_destroy(). This is fine here, but similar code
+    // asynchronously doing a handshake instead of calling
+    // grpc_tcp_server_start() (as in server_secure_chttp2.c) needs to add
+    // synchronization to avoid this case.
+    grpc_transport *transport =
+        grpc_create_chttp2_transport(exec_ctx, args, endpoint, 0);
+    grpc_server_setup_transport(exec_ctx, state->server, transport,
+                                state->accepting_pollset,
+                                grpc_server_get_channel_args(state->server));
+    grpc_chttp2_transport_start_reading(exec_ctx, transport, read_buffer);
+  }
+  // Clean up.
+  grpc_channel_args_destroy(args);
+  grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr);
+  gpr_free(state);
+}
+
+static void on_accept(grpc_exec_ctx *exec_ctx, void *server, grpc_endpoint *tcp,
+                      grpc_pollset *accepting_pollset,
+                      grpc_tcp_server_acceptor *acceptor) {
+  server_connect_state *state = gpr_malloc(sizeof(server_connect_state));
+  state->server = server;
+  state->accepting_pollset = accepting_pollset;
+  state->acceptor = acceptor;
+  state->handshake_mgr = grpc_handshake_manager_create();
+  // TODO(roth): We should really get this timeout value from channel
+  // args instead of hard-coding it.
+  const gpr_timespec deadline = gpr_time_add(
+      gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_seconds(120, GPR_TIMESPAN));
+  grpc_handshake_manager_do_handshake(
+      exec_ctx, state->handshake_mgr, tcp, grpc_server_get_channel_args(server),
+      deadline, acceptor, on_handshake_done, state);
 }
 
 /* Server callback: start listening on our ports */
 static void start(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
                   grpc_pollset **pollsets, size_t pollset_count) {
   grpc_tcp_server *tcp = tcpp;
-  grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, new_transport,
+  grpc_tcp_server_start(exec_ctx, tcp, pollsets, pollset_count, on_accept,
                         server);
 }
 
@@ -74,6 +115,7 @@
 static void destroy(grpc_exec_ctx *exec_ctx, grpc_server *server, void *tcpp,
                     grpc_closure *destroy_done) {
   grpc_tcp_server *tcp = tcpp;
+  grpc_tcp_server_shutdown_listeners(exec_ctx, tcp);
   grpc_tcp_server_unref(exec_ctx, tcp);
   grpc_exec_ctx_sched(exec_ctx, destroy_done, GRPC_ERROR_NONE, NULL);
 }
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 96bf4d6..4350543 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
@@ -67,7 +67,7 @@
       &exec_ctx, server_args, server_endpoint, 0 /* is_client */);
   grpc_endpoint_add_to_pollset(&exec_ctx, server_endpoint, grpc_cq_pollset(cq));
   grpc_server_setup_transport(&exec_ctx, server, transport, NULL, server_args);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
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 c42810e..da3e284 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
@@ -42,6 +42,7 @@
 #include <grpc/support/useful.h>
 #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/http_server_filter.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -58,7 +59,7 @@
   grpc_tcp_server *tcp;
   grpc_server_security_connector *sc;
   grpc_server_credentials *creds;
-  int is_shutdown;
+  bool is_shutdown;
   gpr_mu mu;
   gpr_refcount refcount;
   grpc_closure destroy_closure;
@@ -68,6 +69,12 @@
 typedef struct server_secure_connect {
   server_secure_state *state;
   grpc_pollset *accepting_pollset;
+  grpc_tcp_server_acceptor *acceptor;
+  grpc_handshake_manager *handshake_mgr;
+  // TODO(roth): Remove the following two fields when we eliminate
+  // grpc_server_security_connector_do_handshake().
+  gpr_timespec deadline;
+  grpc_channel_args *args;
 } server_secure_connect;
 
 static void state_ref(server_secure_state *state) { gpr_ref(&state->refcount); }
@@ -89,25 +96,22 @@
                                      grpc_endpoint *secure_endpoint,
                                      grpc_auth_context *auth_context) {
   server_secure_connect *state = statep;
-  grpc_transport *transport;
   if (status == GRPC_SECURITY_OK) {
     if (secure_endpoint) {
       gpr_mu_lock(&state->state->mu);
       if (!state->state->is_shutdown) {
-        transport = grpc_create_chttp2_transport(
+        grpc_transport *transport = grpc_create_chttp2_transport(
             exec_ctx, grpc_server_get_channel_args(state->state->server),
             secure_endpoint, 0);
-        grpc_channel_args *args_copy;
         grpc_arg args_to_add[2];
         args_to_add[0] = grpc_server_credentials_to_arg(state->state->creds);
         args_to_add[1] = grpc_auth_context_to_arg(auth_context);
-        args_copy = grpc_channel_args_copy_and_add(
-            grpc_server_get_channel_args(state->state->server), args_to_add,
-            GPR_ARRAY_SIZE(args_to_add));
+        grpc_channel_args *args_copy = grpc_channel_args_copy_and_add(
+            state->args, args_to_add, GPR_ARRAY_SIZE(args_to_add));
         grpc_server_setup_transport(exec_ctx, state->state->server, transport,
                                     state->accepting_pollset, args_copy);
         grpc_channel_args_destroy(args_copy);
-        grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
+        grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL);
       } else {
         /* We need to consume this here, because the server may already have
          * gone away. */
@@ -118,10 +122,40 @@
   } else {
     gpr_log(GPR_ERROR, "Secure transport failed with error %d", status);
   }
+  grpc_channel_args_destroy(state->args);
   state_unref(state->state);
   gpr_free(state);
 }
 
+static void on_handshake_done(grpc_exec_ctx *exec_ctx, grpc_endpoint *endpoint,
+                              grpc_channel_args *args,
+                              gpr_slice_buffer *read_buffer, void *user_data,
+                              grpc_error *error) {
+  server_secure_connect *state = user_data;
+  if (error != GRPC_ERROR_NONE) {
+    const char *error_str = grpc_error_string(error);
+    gpr_log(GPR_ERROR, "Handshaking failed: %s", error_str);
+    grpc_error_free_string(error_str);
+    GRPC_ERROR_UNREF(error);
+    grpc_channel_args_destroy(args);
+    gpr_free(read_buffer);
+    grpc_handshake_manager_shutdown(exec_ctx, state->handshake_mgr);
+    grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr);
+    state_unref(state->state);
+    gpr_free(state);
+    return;
+  }
+  grpc_handshake_manager_destroy(exec_ctx, state->handshake_mgr);
+  state->handshake_mgr = NULL;
+  // TODO(roth, jboeuf): Convert security connector handshaking to use new
+  // handshake API, and then move the code from on_secure_handshake_done()
+  // into this function.
+  state->args = args;
+  grpc_server_security_connector_do_handshake(
+      exec_ctx, state->state->sc, state->acceptor, endpoint, read_buffer,
+      state->deadline, on_secure_handshake_done, state);
+}
+
 static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
                       grpc_pollset *accepting_pollset,
                       grpc_tcp_server_acceptor *acceptor) {
@@ -129,11 +163,16 @@
   state->state = statep;
   state_ref(state->state);
   state->accepting_pollset = accepting_pollset;
-  grpc_server_security_connector_do_handshake(
-      exec_ctx, state->state->sc, acceptor, tcp,
-      gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                   gpr_time_from_seconds(120, GPR_TIMESPAN)),
-      on_secure_handshake_done, state);
+  state->acceptor = acceptor;
+  state->handshake_mgr = grpc_handshake_manager_create();
+  // TODO(roth): We should really get this timeout value from channel
+  // args instead of hard-coding it.
+  state->deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                 gpr_time_from_seconds(120, GPR_TIMESPAN));
+  grpc_handshake_manager_do_handshake(
+      exec_ctx, state->handshake_mgr, tcp,
+      grpc_server_get_channel_args(state->state->server), state->deadline,
+      acceptor, on_handshake_done, state);
 }
 
 /* Server callback: start listening on our ports */
@@ -162,10 +201,11 @@
   server_secure_state *state = statep;
   grpc_tcp_server *tcp;
   gpr_mu_lock(&state->mu);
-  state->is_shutdown = 1;
+  state->is_shutdown = true;
   state->destroy_callback = callback;
   tcp = state->tcp;
   gpr_mu_unlock(&state->mu);
+  grpc_tcp_server_shutdown_listeners(exec_ctx, tcp);
   grpc_tcp_server_unref(exec_ctx, tcp);
 }
 
@@ -226,7 +266,7 @@
   state->tcp = tcp;
   state->sc = sc;
   state->creds = grpc_server_credentials_ref(creds);
-  state->is_shutdown = 0;
+  state->is_shutdown = false;
   gpr_mu_init(&state->mu);
   gpr_ref_init(&state->refcount, 1);
 
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index d050467..0e8dfb7 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -46,12 +46,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/timeout_encoding.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/support/string.h"
 #include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/timeout_encoding.h"
 #include "src/core/lib/transport/transport_impl.h"
 
 #define DEFAULT_WINDOW 65535
@@ -94,7 +94,8 @@
 
 static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
 static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t, grpc_error *error);
+                                  grpc_chttp2_transport *t, grpc_error *error,
+                                  const char *reason);
 
 /** Set a transport level setting, and push it to our peer */
 static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -876,7 +877,7 @@
       set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
                       "start_writing:nothing_to_write");
     }
-    end_waiting_for_write(exec_ctx, t, GRPC_ERROR_CREATE("Nothing to write"));
+    end_waiting_for_write(exec_ctx, t, GRPC_ERROR_NONE, "Nothing to write");
     if (t->ep && !t->endpoint_reading) {
       destroy_endpoint(exec_ctx, t);
     }
@@ -925,11 +926,18 @@
   }
 }
 
+/* error may be GRPC_ERROR_NONE if there is no error allocated yet.
+   In that case, use "reason" as the text for a new error. */
 static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t, grpc_error *error) {
+                                  grpc_chttp2_transport *t, grpc_error *error,
+                                  const char *reason) {
   grpc_chttp2_stream_global *stream_global;
   while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
                                                          &stream_global)) {
+    if (error == GRPC_ERROR_NONE && reason != NULL) {
+      /* create error object. */
+      error = GRPC_ERROR_CREATE(reason);
+    }
     fail_pending_writes(exec_ctx, &t->global, stream_global,
                         GRPC_ERROR_REF(error));
     GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
@@ -951,7 +959,7 @@
 
   grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
 
-  end_waiting_for_write(exec_ctx, t, error);
+  end_waiting_for_write(exec_ctx, t, error, NULL);
 
   switch (t->executor.write_state) {
     case GRPC_CHTTP2_WRITING_INACTIVE:
@@ -2538,9 +2546,12 @@
 
 void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
                                          grpc_transport *transport,
-                                         gpr_slice *slices, size_t nslices) {
+                                         gpr_slice_buffer *read_buffer) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
   REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
-  gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
+  if (read_buffer != NULL) {
+    gpr_slice_buffer_move_into(read_buffer, &t->read_buffer);
+    gpr_free(read_buffer);
+  }
   reading_action(exec_ctx, t, GRPC_ERROR_NONE);
 }
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index 5da4276..4e2d095 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -44,8 +44,10 @@
     grpc_exec_ctx *exec_ctx, const grpc_channel_args *channel_args,
     grpc_endpoint *ep, int is_client);
 
+/// Takes ownership of \a read_buffer, which (if non-NULL) contains
+/// leftover bytes previously read from the endpoint (e.g., by handshakers).
 void grpc_chttp2_transport_start_reading(grpc_exec_ctx *exec_ctx,
                                          grpc_transport *transport,
-                                         gpr_slice *slices, size_t nslices);
+                                         gpr_slice_buffer *read_buffer);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.c b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
index ebeee37..2cb8205 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.c
@@ -47,10 +47,10 @@
 
 #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/timeout_encoding.h"
 #include "src/core/ext/transport/chttp2/transport/varint.h"
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/timeout_encoding.h"
 
 #define HASH_FRAGMENT_1(x) ((x)&255)
 #define HASH_FRAGMENT_2(x) ((x >> 8) & 255)
@@ -456,9 +456,9 @@
 
 static void deadline_enc(grpc_chttp2_hpack_compressor *c, gpr_timespec deadline,
                          framer_state *st) {
-  char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
+  char timeout_str[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
   grpc_mdelem *mdelem;
-  grpc_chttp2_encode_timeout(
+  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));
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index e1fc0dd..482cd55 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -41,9 +41,9 @@
 
 #include "src/core/ext/transport/chttp2/transport/http2_errors.h"
 #include "src/core/ext/transport/chttp2/transport/status_conversion.h"
-#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/transport/static_metadata.h"
+#include "src/core/lib/transport/timeout_encoding.h"
 
 #define TRANSPORT_FROM_PARSING(tp)                                        \
   ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
@@ -668,8 +668,8 @@
     if (!cached_timeout) {
       /* not already parsed: parse it now, and store the result away */
       cached_timeout = gpr_malloc(sizeof(gpr_timespec));
-      if (!grpc_chttp2_decode_timeout(grpc_mdstr_as_c_string(md->value),
-                                      cached_timeout)) {
+      if (!grpc_http2_decode_timeout(grpc_mdstr_as_c_string(md->value),
+                                     cached_timeout)) {
         gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'",
                 grpc_mdstr_as_c_string(md->value));
         *cached_timeout = gpr_inf_future(GPR_TIMESPAN);
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index e0d8772..8f7a1f5 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -202,6 +202,7 @@
 
   GPR_TIMER_BEGIN("finalize_outbuf", 0);
 
+  bool is_first_data_frame = true;
   while (
       grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
     uint32_t max_outgoing =
@@ -266,6 +267,11 @@
             stream_writing->id, &stream_writing->flow_controlled_buffer,
             send_bytes, is_last_frame, &stream_writing->stats,
             &transport_writing->outbuf);
+        if (is_first_data_frame) {
+          /* TODO(dgq): this is a hack. It'll be fix in a future refactoring */
+          stream_writing->stats.data_bytes -= 5; /* discount grpc framing */
+          is_first_data_frame = false;
+        }
         GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing,
                                       stream_writing, outgoing_window,
                                       send_bytes);
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c
index 25d8aca..029c150 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.c
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.c
@@ -46,189 +46,519 @@
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/transport/metadata_batch.h"
+#include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/transport_impl.h"
 #include "third_party/objective_c/Cronet/cronet_c_for_grpc.h"
 
 #define GRPC_HEADER_SIZE_IN_BYTES 5
 
-// Global flag that gets set with GRPC_TRACE env variable
-int grpc_cronet_trace = 1;
+#define CRONET_LOG(...)                          \
+  do {                                           \
+    if (grpc_cronet_trace) gpr_log(__VA_ARGS__); \
+  } while (0)
 
-// Cronet transport object
+/* TODO (makdharma): Hook up into the wider tracing mechanism */
+int grpc_cronet_trace = 0;
+
+enum e_op_result {
+  ACTION_TAKEN_WITH_CALLBACK,
+  ACTION_TAKEN_NO_CALLBACK,
+  NO_ACTION_POSSIBLE
+};
+
+enum e_op_id {
+  OP_SEND_INITIAL_METADATA = 0,
+  OP_SEND_MESSAGE,
+  OP_SEND_TRAILING_METADATA,
+  OP_RECV_MESSAGE,
+  OP_RECV_INITIAL_METADATA,
+  OP_RECV_TRAILING_METADATA,
+  OP_CANCEL_ERROR,
+  OP_ON_COMPLETE,
+  OP_FAILED,
+  OP_SUCCEEDED,
+  OP_CANCELED,
+  OP_RECV_MESSAGE_AND_ON_COMPLETE,
+  OP_READ_REQ_MADE,
+  OP_NUM_OPS
+};
+
+/* Cronet callbacks. See cronet_c_for_grpc.h for documentation for each. */
+
+static void on_request_headers_sent(cronet_bidirectional_stream *);
+static void on_response_headers_received(
+    cronet_bidirectional_stream *,
+    const cronet_bidirectional_stream_header_array *, const char *);
+static void on_write_completed(cronet_bidirectional_stream *, const char *);
+static void on_read_completed(cronet_bidirectional_stream *, char *, int);
+static void on_response_trailers_received(
+    cronet_bidirectional_stream *,
+    const cronet_bidirectional_stream_header_array *);
+static void on_succeeded(cronet_bidirectional_stream *);
+static void on_failed(cronet_bidirectional_stream *, int);
+static void on_canceled(cronet_bidirectional_stream *);
+static cronet_bidirectional_stream_callback cronet_callbacks = {
+    on_request_headers_sent,
+    on_response_headers_received,
+    on_read_completed,
+    on_write_completed,
+    on_response_trailers_received,
+    on_succeeded,
+    on_failed,
+    on_canceled};
+
+/* Cronet transport object */
 struct grpc_cronet_transport {
   grpc_transport base; /* must be first element in this structure */
   cronet_engine *engine;
   char *host;
 };
-
 typedef struct grpc_cronet_transport grpc_cronet_transport;
 
-enum send_state {
-  CRONET_SEND_IDLE = 0,
-  CRONET_REQ_STARTED,
-  CRONET_SEND_HEADER,
-  CRONET_WRITE,
-  CRONET_WRITE_COMPLETED,
+/* TODO (makdharma): reorder structure for memory efficiency per
+   http://www.catb.org/esr/structure-packing/#_structure_reordering: */
+struct read_state {
+  /* vars to store data coming from server */
+  char *read_buffer;
+  bool length_field_received;
+  int received_bytes;
+  int remaining_bytes;
+  int length_field;
+  char grpc_header_bytes[GRPC_HEADER_SIZE_IN_BYTES];
+  char *payload_field;
+  bool read_stream_closed;
+
+  /* vars for holding data destined for the application */
+  struct grpc_slice_buffer_stream sbs;
+  gpr_slice_buffer read_slice_buffer;
+
+  /* vars for trailing metadata */
+  grpc_chttp2_incoming_metadata_buffer trailing_metadata;
+  bool trailing_metadata_valid;
+
+  /* vars for initial metadata */
+  grpc_chttp2_incoming_metadata_buffer initial_metadata;
 };
 
-enum recv_state {
-  CRONET_RECV_IDLE = 0,
-  CRONET_RECV_READ_LENGTH,
-  CRONET_RECV_READ_DATA,
-  CRONET_RECV_CLOSED,
+struct write_state {
+  char *write_buffer;
 };
 
-static const char *recv_state_name[] = {
-    "CRONET_RECV_IDLE", "CRONET_RECV_READ_LENGTH", "CRONET_RECV_READ_DATA,",
-    "CRONET_RECV_CLOSED"};
-
-// Enum that identifies calling function.
-enum e_caller {
-  PERFORM_STREAM_OP,
-  ON_READ_COMPLETE,
-  ON_RESPONSE_HEADERS_RECEIVED,
-  ON_RESPONSE_TRAILERS_RECEIVED
+/* track state of one stream op */
+struct op_state {
+  bool state_op_done[OP_NUM_OPS];
+  bool state_callback_received[OP_NUM_OPS];
+  /* data structure for storing data coming from server */
+  struct read_state rs;
+  /* data structure for storing data going to the server */
+  struct write_state ws;
 };
 
-enum callback_id {
-  CB_SEND_INITIAL_METADATA = 0,
-  CB_SEND_MESSAGE,
-  CB_SEND_TRAILING_METADATA,
-  CB_RECV_MESSAGE,
-  CB_RECV_INITIAL_METADATA,
-  CB_RECV_TRAILING_METADATA,
-  CB_NUM_CALLBACKS
+struct op_and_state {
+  grpc_transport_stream_op op;
+  struct op_state state;
+  bool done;
+  struct stream_obj *s;      /* Pointer back to the stream object */
+  struct op_and_state *next; /* next op_and_state in the linked list */
+};
+
+struct op_storage {
+  int num_pending_ops;
+  struct op_and_state *head;
 };
 
 struct stream_obj {
-  // we store received bytes here as they trickle in.
-  gpr_slice_buffer write_slice_buffer;
+  struct op_and_state *oas;
+  grpc_transport_stream_op *curr_op;
+  grpc_cronet_transport curr_ct;
+  grpc_stream *curr_gs;
   cronet_bidirectional_stream *cbs;
-  gpr_slice slice;
-  gpr_slice_buffer read_slice_buffer;
-  struct grpc_slice_buffer_stream sbs;
-  char *read_buffer;
-  int remaining_read_bytes;
-  int total_read_bytes;
-
-  char *write_buffer;
-  size_t write_buffer_size;
-
-  // Hold the URL
-  char *url;
-
-  bool response_headers_received;
-  bool read_requested;
-  bool response_trailers_received;
-  bool read_closed;
-
-  // Recv message stuff
-  grpc_byte_buffer **recv_message;
-  // Initial metadata stuff
-  grpc_metadata_batch *recv_initial_metadata;
-  // Trailing metadata stuff
-  grpc_metadata_batch *recv_trailing_metadata;
-  grpc_chttp2_incoming_metadata_buffer imb;
-
-  // This mutex protects receive state machine execution
-  gpr_mu recv_mu;
-  // we can queue up up to 2 callbacks for each OP
-  grpc_closure *callback_list[CB_NUM_CALLBACKS][2];
-
-  // storage for header
-  cronet_bidirectional_stream_header *headers;
-  uint32_t num_headers;
   cronet_bidirectional_stream_header_array header_array;
-  // state tracking
-  enum recv_state cronet_recv_state;
-  enum send_state cronet_send_state;
-};
 
+  /* Stream level state. Some state will be tracked both at stream and stream_op
+   * level */
+  struct op_state state;
+
+  /* OP storage */
+  struct op_storage storage;
+
+  /* Mutex to protect storage */
+  gpr_mu mu;
+};
 typedef struct stream_obj stream_obj;
 
-static void next_send_step(stream_obj *s);
-static void next_recv_step(stream_obj *s, enum e_caller caller);
+static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
+                                          struct op_and_state *oas);
 
-static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                                   grpc_stream *gs, grpc_pollset *pollset) {}
+/*
+  Utility function to translate enum into string for printing
+*/
+static const char *op_result_string(enum e_op_result i) {
+  switch (i) {
+    case ACTION_TAKEN_WITH_CALLBACK:
+      return "ACTION_TAKEN_WITH_CALLBACK";
+    case ACTION_TAKEN_NO_CALLBACK:
+      return "ACTION_TAKEN_NO_CALLBACK";
+    case NO_ACTION_POSSIBLE:
+      return "NO_ACTION_POSSIBLE";
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
 
-static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
-                                       grpc_transport *gt, grpc_stream *gs,
-                                       grpc_pollset_set *pollset_set) {}
+static const char *op_id_string(enum e_op_id i) {
+  switch (i) {
+    case OP_SEND_INITIAL_METADATA:
+      return "OP_SEND_INITIAL_METADATA";
+    case OP_SEND_MESSAGE:
+      return "OP_SEND_MESSAGE";
+    case OP_SEND_TRAILING_METADATA:
+      return "OP_SEND_TRAILING_METADATA";
+    case OP_RECV_MESSAGE:
+      return "OP_RECV_MESSAGE";
+    case OP_RECV_INITIAL_METADATA:
+      return "OP_RECV_INITIAL_METADATA";
+    case OP_RECV_TRAILING_METADATA:
+      return "OP_RECV_TRAILING_METADATA";
+    case OP_CANCEL_ERROR:
+      return "OP_CANCEL_ERROR";
+    case OP_ON_COMPLETE:
+      return "OP_ON_COMPLETE";
+    case OP_FAILED:
+      return "OP_FAILED";
+    case OP_SUCCEEDED:
+      return "OP_SUCCEEDED";
+    case OP_CANCELED:
+      return "OP_CANCELED";
+    case OP_RECV_MESSAGE_AND_ON_COMPLETE:
+      return "OP_RECV_MESSAGE_AND_ON_COMPLETE";
+    case OP_READ_REQ_MADE:
+      return "OP_READ_REQ_MADE";
+    case OP_NUM_OPS:
+      return "OP_NUM_OPS";
+  }
+  return "UNKNOWN";
+}
 
-static void enqueue_callbacks(grpc_closure *callback_list[]) {
+/*
+  Add a new stream op to op storage.
+*/
+static void add_to_storage(struct stream_obj *s, grpc_transport_stream_op *op) {
+  struct op_storage *storage = &s->storage;
+  /* add new op at the beginning of the linked list. The memory is freed
+  in remove_from_storage */
+  struct op_and_state *new_op = gpr_malloc(sizeof(struct op_and_state));
+  memcpy(&new_op->op, op, sizeof(grpc_transport_stream_op));
+  memset(&new_op->state, 0, sizeof(new_op->state));
+  new_op->s = s;
+  new_op->done = false;
+  gpr_mu_lock(&s->mu);
+  new_op->next = storage->head;
+  storage->head = new_op;
+  storage->num_pending_ops++;
+  CRONET_LOG(GPR_DEBUG, "adding new op %p. %d in the queue.", new_op,
+             storage->num_pending_ops);
+  gpr_mu_unlock(&s->mu);
+}
+
+/*
+  Traverse the linked list and delete op and free memory
+*/
+static void remove_from_storage(struct stream_obj *s,
+                                struct op_and_state *oas) {
+  struct op_and_state *curr;
+  if (s->storage.head == NULL || oas == NULL) {
+    return;
+  }
+  if (s->storage.head == oas) {
+    s->storage.head = oas->next;
+    gpr_free(oas);
+    s->storage.num_pending_ops--;
+    CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas,
+               s->storage.num_pending_ops);
+  } else {
+    for (curr = s->storage.head; curr != NULL; curr = curr->next) {
+      if (curr->next == oas) {
+        curr->next = oas->next;
+        s->storage.num_pending_ops--;
+        CRONET_LOG(GPR_DEBUG, "Freed %p. Now %d in the queue", oas,
+                   s->storage.num_pending_ops);
+        gpr_free(oas);
+        break;
+      } else if (curr->next == NULL) {
+        CRONET_LOG(GPR_ERROR, "Reached end of LL and did not find op to free");
+      }
+    }
+  }
+}
+
+/*
+  Cycle through ops and try to take next action. Break when either
+  an action with callback is taken, or no action is possible.
+  This can be executed from the Cronet network thread via cronet callback
+  or on the application supplied thread via the perform_stream_op function.
+*/
+static void execute_from_storage(stream_obj *s) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  if (callback_list[0]) {
-    grpc_exec_ctx_sched(&exec_ctx, callback_list[0], GRPC_ERROR_NONE, NULL);
-    callback_list[0] = NULL;
+  gpr_mu_lock(&s->mu);
+  for (struct op_and_state *curr = s->storage.head; curr != NULL;) {
+    CRONET_LOG(GPR_DEBUG, "calling op at %p. done = %d", curr, curr->done);
+    GPR_ASSERT(curr->done == 0);
+    enum e_op_result result = execute_stream_op(&exec_ctx, curr);
+    CRONET_LOG(GPR_DEBUG, "execute_stream_op[%p] returns %s", curr,
+               op_result_string(result));
+    /* if this op is done, then remove it and free memory */
+    if (curr->done) {
+      struct op_and_state *next = curr->next;
+      remove_from_storage(s, curr);
+      curr = next;
+    }
+    /* continue processing the same op if ACTION_TAKEN_WITHOUT_CALLBACK */
+    if (result == NO_ACTION_POSSIBLE) {
+      curr = curr->next;
+    } else if (result == ACTION_TAKEN_WITH_CALLBACK) {
+      break;
+    }
   }
-  if (callback_list[1]) {
-    grpc_exec_ctx_sched(&exec_ctx, callback_list[1], GRPC_ERROR_NONE, NULL);
-    callback_list[1] = NULL;
-  }
+  gpr_mu_unlock(&s->mu);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void on_canceled(cronet_bidirectional_stream *stream) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "on_canceled %p", stream);
-  }
-}
-
+/*
+  Cronet callback
+*/
 static void on_failed(cronet_bidirectional_stream *stream, int net_error) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "on_failed %p, error = %d", stream, net_error);
+  CRONET_LOG(GPR_DEBUG, "on_failed(%p, %d)", stream, net_error);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  cronet_bidirectional_stream_destroy(s->cbs);
+  s->state.state_callback_received[OP_FAILED] = true;
+  s->cbs = NULL;
+  if (s->header_array.headers) {
+    gpr_free(s->header_array.headers);
+    s->header_array.headers = NULL;
   }
+  if (s->state.ws.write_buffer) {
+    gpr_free(s->state.ws.write_buffer);
+    s->state.ws.write_buffer = NULL;
+  }
+  execute_from_storage(s);
 }
 
+/*
+  Cronet callback
+*/
+static void on_canceled(cronet_bidirectional_stream *stream) {
+  CRONET_LOG(GPR_DEBUG, "on_canceled(%p)", stream);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  cronet_bidirectional_stream_destroy(s->cbs);
+  s->state.state_callback_received[OP_CANCELED] = true;
+  s->cbs = NULL;
+  if (s->header_array.headers) {
+    gpr_free(s->header_array.headers);
+    s->header_array.headers = NULL;
+  }
+  if (s->state.ws.write_buffer) {
+    gpr_free(s->state.ws.write_buffer);
+    s->state.ws.write_buffer = NULL;
+  }
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
 static void on_succeeded(cronet_bidirectional_stream *stream) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "on_succeeded %p", stream);
+  CRONET_LOG(GPR_DEBUG, "on_succeeded(%p)", stream);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  cronet_bidirectional_stream_destroy(s->cbs);
+  s->state.state_callback_received[OP_SUCCEEDED] = true;
+  s->cbs = NULL;
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_request_headers_sent(cronet_bidirectional_stream *stream) {
+  CRONET_LOG(GPR_DEBUG, "W: on_request_headers_sent(%p)", stream);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  s->state.state_op_done[OP_SEND_INITIAL_METADATA] = true;
+  s->state.state_callback_received[OP_SEND_INITIAL_METADATA] = true;
+  /* Free the memory allocated for headers */
+  if (s->header_array.headers) {
+    gpr_free(s->header_array.headers);
+    s->header_array.headers = NULL;
+  }
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_response_headers_received(
+    cronet_bidirectional_stream *stream,
+    const cronet_bidirectional_stream_header_array *headers,
+    const char *negotiated_protocol) {
+  CRONET_LOG(GPR_DEBUG, "R: on_response_headers_received(%p, %p, %s)", stream,
+             headers, negotiated_protocol);
+  stream_obj *s = (stream_obj *)stream->annotation;
+  memset(&s->state.rs.initial_metadata, 0,
+         sizeof(s->state.rs.initial_metadata));
+  grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.initial_metadata);
+  for (size_t i = 0; i < headers->count; i++) {
+    grpc_chttp2_incoming_metadata_buffer_add(
+        &s->state.rs.initial_metadata,
+        grpc_mdelem_from_metadata_strings(
+            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;
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_write_completed(cronet_bidirectional_stream *stream,
+                               const char *data) {
+  stream_obj *s = (stream_obj *)stream->annotation;
+  CRONET_LOG(GPR_DEBUG, "W: on_write_completed(%p, %s)", stream, data);
+  if (s->state.ws.write_buffer) {
+    gpr_free(s->state.ws.write_buffer);
+    s->state.ws.write_buffer = NULL;
+  }
+  s->state.state_callback_received[OP_SEND_MESSAGE] = true;
+  execute_from_storage(s);
+}
+
+/*
+  Cronet callback
+*/
+static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
+                              int count) {
+  stream_obj *s = (stream_obj *)stream->annotation;
+  CRONET_LOG(GPR_DEBUG, "R: on_read_completed(%p, %p, %d)", stream, data,
+             count);
+  s->state.state_callback_received[OP_RECV_MESSAGE] = true;
+  if (count > 0) {
+    s->state.rs.received_bytes += count;
+    s->state.rs.remaining_bytes -= count;
+    if (s->state.rs.remaining_bytes > 0) {
+      CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
+      s->state.state_op_done[OP_READ_REQ_MADE] = true;
+      cronet_bidirectional_stream_read(
+          s->cbs, s->state.rs.read_buffer + s->state.rs.received_bytes,
+          s->state.rs.remaining_bytes);
+    } else {
+      execute_from_storage(s);
+    }
+  } else {
+    s->state.rs.read_stream_closed = true;
+    execute_from_storage(s);
   }
 }
 
+/*
+  Cronet callback
+*/
 static void on_response_trailers_received(
     cronet_bidirectional_stream *stream,
     const cronet_bidirectional_stream_header_array *trailers) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "R: on_response_trailers_received");
-  }
+  CRONET_LOG(GPR_DEBUG, "R: on_response_trailers_received(%p,%p)", stream,
+             trailers);
   stream_obj *s = (stream_obj *)stream->annotation;
-
-  memset(&s->imb, 0, sizeof(s->imb));
-  grpc_chttp2_incoming_metadata_buffer_init(&s->imb);
-  unsigned int i = 0;
-  for (i = 0; i < trailers->count; i++) {
+  memset(&s->state.rs.trailing_metadata, 0,
+         sizeof(s->state.rs.trailing_metadata));
+  s->state.rs.trailing_metadata_valid = false;
+  grpc_chttp2_incoming_metadata_buffer_init(&s->state.rs.trailing_metadata);
+  for (size_t i = 0; i < trailers->count; i++) {
+    CRONET_LOG(GPR_DEBUG, "trailer key=%s, value=%s", trailers->headers[i].key,
+               trailers->headers[i].value);
     grpc_chttp2_incoming_metadata_buffer_add(
-        &s->imb, grpc_mdelem_from_metadata_strings(
-                     grpc_mdstr_from_string(trailers->headers[i].key),
-                     grpc_mdstr_from_string(trailers->headers[i].value)));
+        &s->state.rs.trailing_metadata,
+        grpc_mdelem_from_metadata_strings(
+            grpc_mdstr_from_string(trailers->headers[i].key),
+            grpc_mdstr_from_string(trailers->headers[i].value)));
+    s->state.rs.trailing_metadata_valid = true;
   }
-  s->response_trailers_received = true;
-  next_recv_step(s, ON_RESPONSE_TRAILERS_RECEIVED);
+  s->state.state_callback_received[OP_RECV_TRAILING_METADATA] = true;
+  execute_from_storage(s);
 }
 
-static void on_write_completed(cronet_bidirectional_stream *stream,
-                               const char *data) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "W: on_write_completed");
-  }
-  stream_obj *s = (stream_obj *)stream->annotation;
-  enqueue_callbacks(s->callback_list[CB_SEND_MESSAGE]);
-  s->cronet_send_state = CRONET_WRITE_COMPLETED;
-  next_send_step(s);
+/*
+ Utility function that takes the data from s->write_slice_buffer and assembles
+ into a contiguous byte stream with 5 byte gRPC header prepended.
+*/
+static void create_grpc_frame(gpr_slice_buffer *write_slice_buffer,
+                              char **pp_write_buffer,
+                              size_t *p_write_buffer_size) {
+  gpr_slice slice = gpr_slice_buffer_take_first(write_slice_buffer);
+  size_t length = GPR_SLICE_LENGTH(slice);
+  *p_write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
+  /* This is freed in the on_write_completed callback */
+  char *write_buffer = gpr_malloc(length + GRPC_HEADER_SIZE_IN_BYTES);
+  *pp_write_buffer = write_buffer;
+  uint8_t *p = (uint8_t *)write_buffer;
+  /* Append 5 byte header */
+  *p++ = 0;
+  *p++ = (uint8_t)(length >> 24);
+  *p++ = (uint8_t)(length >> 16);
+  *p++ = (uint8_t)(length >> 8);
+  *p++ = (uint8_t)(length);
+  /* append actual data */
+  memcpy(p, GPR_SLICE_START_PTR(slice), length);
 }
 
-static void process_recv_message(stream_obj *s, const uint8_t *recv_data) {
-  gpr_slice read_data_slice = gpr_slice_malloc((uint32_t)s->total_read_bytes);
-  uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice);
-  if (s->total_read_bytes > 0) {
-    // Only copy if there is non-zero number of bytes
-    memcpy(dst_p, recv_data, (size_t)s->total_read_bytes);
-    gpr_slice_buffer_add(&s->read_slice_buffer, read_data_slice);
+/*
+ Convert metadata in a format that Cronet can consume
+*/
+static void convert_metadata_to_cronet_headers(
+    grpc_linked_mdelem *head, const char *host, char **pp_url,
+    cronet_bidirectional_stream_header **pp_headers, size_t *p_num_headers) {
+  grpc_linked_mdelem *curr = head;
+  /* Walk the linked list and get number of header fields */
+  size_t num_headers_available = 0;
+  while (curr != NULL) {
+    curr = curr->next;
+    num_headers_available++;
   }
-  grpc_slice_buffer_stream_init(&s->sbs, &s->read_slice_buffer, 0);
-  *s->recv_message = (grpc_byte_buffer *)&s->sbs;
+  /* Allocate enough memory. It is freed in the on_request_headers_sent callback
+   */
+  cronet_bidirectional_stream_header *headers =
+      (cronet_bidirectional_stream_header *)gpr_malloc(
+          sizeof(cronet_bidirectional_stream_header) * num_headers_available);
+  *pp_headers = headers;
+
+  /* Walk the linked list again, this time copying the header fields.
+    s->num_headers can be less than num_headers_available, as some headers
+    are not used for cronet.
+    TODO (makdharma): Eliminate need to traverse the LL second time for perf.
+   */
+  curr = head;
+  size_t num_headers = 0;
+  while (num_headers < num_headers_available) {
+    grpc_mdelem *mdelem = curr->md;
+    curr = curr->next;
+    const char *key = grpc_mdstr_as_c_string(mdelem->key);
+    const char *value = grpc_mdstr_as_c_string(mdelem->value);
+    if (mdelem->key == GRPC_MDSTR_METHOD || mdelem->key == GRPC_MDSTR_SCHEME ||
+        mdelem->key == GRPC_MDSTR_AUTHORITY) {
+      /* Cronet populates these fields on its own */
+      continue;
+    }
+    if (mdelem->key == GRPC_MDSTR_PATH) {
+      /* Create URL by appending :path value to the hostname */
+      gpr_asprintf(pp_url, "https://%s%s", host, value);
+      continue;
+    }
+    CRONET_LOG(GPR_DEBUG, "header %s = %s", key, value);
+    headers[num_headers].key = key;
+    headers[num_headers].value = value;
+    num_headers++;
+    if (curr == NULL) {
+      break;
+    }
+  }
+  *p_num_headers = (size_t)num_headers;
 }
 
 static int parse_grpc_header(const uint8_t *data) {
@@ -241,422 +571,439 @@
   return length;
 }
 
-static void on_read_completed(cronet_bidirectional_stream *stream, char *data,
-                              int count) {
-  stream_obj *s = (stream_obj *)stream->annotation;
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "R: on_read_completed count=%d, total=%d, remaining=%d",
-            count, s->total_read_bytes, s->remaining_read_bytes);
-  }
-  if (count > 0) {
-    GPR_ASSERT(s->recv_message);
-    s->remaining_read_bytes -= count;
-    next_recv_step(s, ON_READ_COMPLETE);
-  } else {
-    s->read_closed = true;
-    next_recv_step(s, ON_READ_COMPLETE);
-  }
-}
-
-static void on_response_headers_received(
-    cronet_bidirectional_stream *stream,
-    const cronet_bidirectional_stream_header_array *headers,
-    const char *negotiated_protocol) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "R: on_response_headers_received");
-  }
-  stream_obj *s = (stream_obj *)stream->annotation;
-  enqueue_callbacks(s->callback_list[CB_RECV_INITIAL_METADATA]);
-  s->response_headers_received = true;
-  next_recv_step(s, ON_RESPONSE_HEADERS_RECEIVED);
-}
-
-static void on_request_headers_sent(cronet_bidirectional_stream *stream) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "W: on_request_headers_sent");
-  }
-  stream_obj *s = (stream_obj *)stream->annotation;
-  enqueue_callbacks(s->callback_list[CB_SEND_INITIAL_METADATA]);
-  s->cronet_send_state = CRONET_SEND_HEADER;
-  next_send_step(s);
-}
-
-// Callback function pointers (invoked by cronet in response to events)
-static cronet_bidirectional_stream_callback callbacks = {
-    on_request_headers_sent,
-    on_response_headers_received,
-    on_read_completed,
-    on_write_completed,
-    on_response_trailers_received,
-    on_succeeded,
-    on_failed,
-    on_canceled};
-
-static void invoke_closing_callback(stream_obj *s) {
-  grpc_chttp2_incoming_metadata_buffer_publish(&s->imb,
-                                               s->recv_trailing_metadata);
-  if (s->callback_list[CB_RECV_TRAILING_METADATA]) {
-    enqueue_callbacks(s->callback_list[CB_RECV_TRAILING_METADATA]);
-  }
-}
-
-static void set_recv_state(stream_obj *s, enum recv_state state) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "next_state = %s", recv_state_name[state]);
-  }
-  s->cronet_recv_state = state;
-}
-
-// This is invoked from perform_stream_op, and all on_xxxx callbacks.
-static void next_recv_step(stream_obj *s, enum e_caller caller) {
-  gpr_mu_lock(&s->recv_mu);
-  switch (s->cronet_recv_state) {
-    case CRONET_RECV_IDLE:
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_IDLE");
+/*
+  Op Execution: Decide if one of the actions contained in the stream op can be
+  executed. This is the heart of the state machine.
+*/
+static bool op_can_be_run(grpc_transport_stream_op *curr_op,
+                          struct op_state *stream_state,
+                          struct op_state *op_state, enum e_op_id op_id) {
+  bool result = true;
+  /* When call is canceled, every op can be run, except under following
+  conditions
+  */
+  bool is_canceled_of_failed = stream_state->state_op_done[OP_CANCEL_ERROR] ||
+                               stream_state->state_callback_received[OP_FAILED];
+  if (is_canceled_of_failed) {
+    if (op_id == OP_SEND_INITIAL_METADATA) result = false;
+    if (op_id == OP_SEND_MESSAGE) result = false;
+    if (op_id == OP_SEND_TRAILING_METADATA) result = false;
+    if (op_id == OP_CANCEL_ERROR) result = false;
+    /* already executed */
+    if (op_id == OP_RECV_INITIAL_METADATA &&
+        stream_state->state_op_done[OP_RECV_INITIAL_METADATA])
+      result = false;
+    if (op_id == OP_RECV_MESSAGE &&
+        stream_state->state_op_done[OP_RECV_MESSAGE])
+      result = false;
+    if (op_id == OP_RECV_TRAILING_METADATA &&
+        stream_state->state_op_done[OP_RECV_TRAILING_METADATA])
+      result = false;
+  } else if (op_id == OP_SEND_INITIAL_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_SEND_INITIAL_METADATA]) result = false;
+  } else if (op_id == OP_RECV_INITIAL_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_RECV_INITIAL_METADATA]) result = false;
+    /* we haven't sent headers yet. */
+    else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
+      result = false;
+    /* we haven't received headers yet. */
+    else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA])
+      result = false;
+  } else if (op_id == OP_SEND_MESSAGE) {
+    /* already executed (note we're checking op specific state, not stream
+     state) */
+    if (op_state->state_op_done[OP_SEND_MESSAGE]) result = false;
+    /* we haven't sent headers yet. */
+    else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
+      result = false;
+  } else if (op_id == OP_RECV_MESSAGE) {
+    /* already executed */
+    if (op_state->state_op_done[OP_RECV_MESSAGE]) result = false;
+    /* we haven't received headers yet. */
+    else if (!stream_state->state_callback_received[OP_RECV_INITIAL_METADATA])
+      result = false;
+  } else if (op_id == OP_RECV_TRAILING_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_RECV_TRAILING_METADATA]) result = false;
+    /* we have asked for but haven't received message yet. */
+    else if (stream_state->state_op_done[OP_READ_REQ_MADE] &&
+             !stream_state->state_op_done[OP_RECV_MESSAGE])
+      result = false;
+    /* we haven't received trailers  yet. */
+    else if (!stream_state->state_callback_received[OP_RECV_TRAILING_METADATA])
+      result = false;
+    /* we haven't received on_succeeded  yet. */
+    else if (!stream_state->state_callback_received[OP_SUCCEEDED])
+      result = false;
+  } else if (op_id == OP_SEND_TRAILING_METADATA) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_SEND_TRAILING_METADATA]) result = false;
+    /* we haven't sent initial metadata yet */
+    else if (!stream_state->state_callback_received[OP_SEND_INITIAL_METADATA])
+      result = false;
+    /* we haven't sent message yet */
+    else if (curr_op->send_message &&
+             !stream_state->state_op_done[OP_SEND_MESSAGE])
+      result = false;
+    /* we haven't got on_write_completed for the send yet */
+    else if (stream_state->state_op_done[OP_SEND_MESSAGE] &&
+             !stream_state->state_callback_received[OP_SEND_MESSAGE])
+      result = false;
+  } else if (op_id == OP_CANCEL_ERROR) {
+    /* already executed */
+    if (stream_state->state_op_done[OP_CANCEL_ERROR]) result = false;
+  } else if (op_id == OP_ON_COMPLETE) {
+    /* already executed (note we're checking op specific state, not stream
+    state) */
+    if (op_state->state_op_done[OP_ON_COMPLETE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    }
+    /* Check if every op that was asked for is done. */
+    else if (curr_op->send_initial_metadata &&
+             !stream_state->state_callback_received[OP_SEND_INITIAL_METADATA]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->send_message &&
+               !op_state->state_op_done[OP_SEND_MESSAGE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->send_message &&
+               !stream_state->state_callback_received[OP_SEND_MESSAGE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->send_trailing_metadata &&
+               !stream_state->state_op_done[OP_SEND_TRAILING_METADATA]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->recv_initial_metadata &&
+               !stream_state->state_op_done[OP_RECV_INITIAL_METADATA]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->recv_message &&
+               !stream_state->state_op_done[OP_RECV_MESSAGE]) {
+      CRONET_LOG(GPR_DEBUG, "Because");
+      result = false;
+    } else if (curr_op->recv_trailing_metadata) {
+      /* We aren't done with trailing metadata yet */
+      if (!stream_state->state_op_done[OP_RECV_TRAILING_METADATA]) {
+        CRONET_LOG(GPR_DEBUG, "Because");
+        result = false;
       }
-      if (caller == PERFORM_STREAM_OP ||
-          caller == ON_RESPONSE_HEADERS_RECEIVED) {
-        if (s->read_closed && s->response_trailers_received) {
-          invoke_closing_callback(s);
-          set_recv_state(s, CRONET_RECV_CLOSED);
-        } else if (s->response_headers_received == true &&
-                   s->read_requested == true) {
-          set_recv_state(s, CRONET_RECV_READ_LENGTH);
-          s->total_read_bytes = s->remaining_read_bytes =
-              GRPC_HEADER_SIZE_IN_BYTES;
-          GPR_ASSERT(s->read_buffer);
-          if (grpc_cronet_trace) {
-            gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
-          }
-          cronet_bidirectional_stream_read(s->cbs, s->read_buffer,
-                                           s->remaining_read_bytes);
+      /* We've asked for actual message in an earlier op, and it hasn't been
+        delivered yet. */
+      else if (stream_state->state_op_done[OP_READ_REQ_MADE]) {
+        /* If this op is not the one asking for read, (which means some earlier
+          op has asked), and the read hasn't been delivered. */
+        if (!curr_op->recv_message &&
+            !stream_state->state_callback_received[OP_SUCCEEDED]) {
+          CRONET_LOG(GPR_DEBUG, "Because");
+          result = false;
         }
       }
-      break;
-    case CRONET_RECV_READ_LENGTH:
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_LENGTH");
-      }
-      if (caller == ON_READ_COMPLETE) {
-        if (s->read_closed) {
-          invoke_closing_callback(s);
-          enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
-          set_recv_state(s, CRONET_RECV_CLOSED);
-        } else {
-          GPR_ASSERT(s->remaining_read_bytes == 0);
-          set_recv_state(s, CRONET_RECV_READ_DATA);
-          s->total_read_bytes = s->remaining_read_bytes =
-              parse_grpc_header((const uint8_t *)s->read_buffer);
-          s->read_buffer =
-              gpr_realloc(s->read_buffer, (uint32_t)s->remaining_read_bytes);
-          GPR_ASSERT(s->read_buffer);
-          if (grpc_cronet_trace) {
-            gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
-          }
-          if (s->remaining_read_bytes > 0) {
-            cronet_bidirectional_stream_read(s->cbs, (char *)s->read_buffer,
-                                             s->remaining_read_bytes);
-          } else {
-            // Calling the closing callback directly since this is a 0 byte read
-            // for an empty message.
-            process_recv_message(s, NULL);
-            enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
-            invoke_closing_callback(s);
-            set_recv_state(s, CRONET_RECV_CLOSED);
-          }
-        }
-      }
-      break;
-    case CRONET_RECV_READ_DATA:
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_DATA");
-      }
-      if (caller == ON_READ_COMPLETE) {
-        if (s->remaining_read_bytes > 0) {
-          int offset = s->total_read_bytes - s->remaining_read_bytes;
-          GPR_ASSERT(s->read_buffer);
-          if (grpc_cronet_trace) {
-            gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()");
-          }
-          cronet_bidirectional_stream_read(
-              s->cbs, (char *)s->read_buffer + offset, s->remaining_read_bytes);
-        } else {
-          gpr_slice_buffer_init(&s->read_slice_buffer);
-          uint8_t *p = (uint8_t *)s->read_buffer;
-          process_recv_message(s, p);
-          set_recv_state(s, CRONET_RECV_IDLE);
-          enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]);
-        }
-      }
-      break;
-    case CRONET_RECV_CLOSED:
-      break;
-    default:
-      GPR_ASSERT(0);  // Should not reach here
-      break;
+    }
+    /* We should see at least one on_write_completed for the trailers that we
+      sent */
+    else if (curr_op->send_trailing_metadata &&
+             !stream_state->state_callback_received[OP_SEND_MESSAGE])
+      result = false;
   }
-  gpr_mu_unlock(&s->recv_mu);
+  CRONET_LOG(GPR_DEBUG, "op_can_be_run %s : %s", op_id_string(op_id),
+             result ? "YES" : "NO");
+  return result;
 }
 
-// This function takes the data from s->write_slice_buffer and assembles into
-// a contiguous byte stream with 5 byte gRPC header prepended.
-static void create_grpc_frame(stream_obj *s) {
-  gpr_slice slice = gpr_slice_buffer_take_first(&s->write_slice_buffer);
-  uint8_t *raw_data = GPR_SLICE_START_PTR(slice);
-  size_t length = GPR_SLICE_LENGTH(slice);
-  s->write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES;
-  s->write_buffer = gpr_realloc(s->write_buffer, s->write_buffer_size);
-  uint8_t *p = (uint8_t *)s->write_buffer;
-  // Append 5 byte header
-  *p++ = 0;
-  *p++ = (uint8_t)(length >> 24);
-  *p++ = (uint8_t)(length >> 16);
-  *p++ = (uint8_t)(length >> 8);
-  *p++ = (uint8_t)(length);
-  // append actual data
-  memcpy(p, raw_data, length);
-}
-
-static void do_write(stream_obj *s) {
-  gpr_slice_buffer *sb = &s->write_slice_buffer;
-  GPR_ASSERT(sb->count <= 1);
-  if (sb->count > 0) {
-    create_grpc_frame(s);
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write");
-    }
-    cronet_bidirectional_stream_write(s->cbs, s->write_buffer,
-                                      (int)s->write_buffer_size, false);
-  }
-}
-
-//
-static void next_send_step(stream_obj *s) {
-  switch (s->cronet_send_state) {
-    case CRONET_SEND_IDLE:
-      GPR_ASSERT(
-          s->cbs);  // cronet_bidirectional_stream is not initialized yet.
-      s->cronet_send_state = CRONET_REQ_STARTED;
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_start to %s", s->url);
-      }
-      cronet_bidirectional_stream_start(s->cbs, s->url, 0, "POST",
-                                        &s->header_array, false);
-      // we no longer need the memory that was allocated earlier.
-      gpr_free(s->header_array.headers);
-      break;
-    case CRONET_SEND_HEADER:
-      do_write(s);
-      s->cronet_send_state = CRONET_WRITE;
-      break;
-    case CRONET_WRITE_COMPLETED:
-      do_write(s);
-      break;
-    default:
-      GPR_ASSERT(0);
-      break;
-  }
-}
-
-static void convert_metadata_to_cronet_headers(grpc_linked_mdelem *head,
-                                               const char *host,
-                                               stream_obj *s) {
-  grpc_linked_mdelem *curr = head;
-  // Walk the linked list and get number of header fields
-  uint32_t num_headers_available = 0;
-  while (curr != NULL) {
-    curr = curr->next;
-    num_headers_available++;
-  }
-  // Allocate enough memory
-  s->headers = (cronet_bidirectional_stream_header *)gpr_malloc(
-      sizeof(cronet_bidirectional_stream_header) * num_headers_available);
-
-  // Walk the linked list again, this time copying the header fields.
-  // s->num_headers
-  // can be less than num_headers_available, as some headers are not used for
-  // cronet
-  curr = head;
-  s->num_headers = 0;
-  while (s->num_headers < num_headers_available) {
-    grpc_mdelem *mdelem = curr->md;
-    curr = curr->next;
-    const char *key = grpc_mdstr_as_c_string(mdelem->key);
-    const char *value = grpc_mdstr_as_c_string(mdelem->value);
-    if (strcmp(key, ":scheme") == 0 || strcmp(key, ":method") == 0 ||
-        strcmp(key, ":authority") == 0) {
-      // Cronet populates these fields on its own.
-      continue;
-    }
-    if (strcmp(key, ":path") == 0) {
-      // Create URL by appending :path value to the hostname
-      gpr_asprintf(&s->url, "https://%s%s", host, value);
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "extracted URL = %s", s->url);
-      }
-      continue;
-    }
-    s->headers[s->num_headers].key = key;
-    s->headers[s->num_headers].value = value;
-    s->num_headers++;
-    if (curr == NULL) {
-      break;
-    }
-  }
-}
-
-static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                              grpc_stream *gs, grpc_transport_stream_op *op) {
-  grpc_cronet_transport *ct = (grpc_cronet_transport *)gt;
-  GPR_ASSERT(ct->engine);
-  stream_obj *s = (stream_obj *)gs;
-  if (op->recv_trailing_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG,
-              "perform_stream_op - recv_trailing_metadata: on_complete=%p",
-              op->on_complete);
-    }
-    s->recv_trailing_metadata = op->recv_trailing_metadata;
-    GPR_ASSERT(!s->callback_list[CB_RECV_TRAILING_METADATA][0]);
-    s->callback_list[CB_RECV_TRAILING_METADATA][0] = op->on_complete;
-  }
-  if (op->recv_message) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "perform_stream_op - recv_message: on_complete=%p",
-              op->on_complete);
-    }
-    s->recv_message = (grpc_byte_buffer **)op->recv_message;
-    GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][0]);
-    GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][1]);
-    s->callback_list[CB_RECV_MESSAGE][0] = op->recv_message_ready;
-    s->callback_list[CB_RECV_MESSAGE][1] = op->on_complete;
-    s->read_requested = true;
-    next_recv_step(s, PERFORM_STREAM_OP);
-  }
-  if (op->recv_initial_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "perform_stream_op - recv_initial_metadata:=%p",
-              op->on_complete);
-    }
-    s->recv_initial_metadata = op->recv_initial_metadata;
-    GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][0]);
-    GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][1]);
-    s->callback_list[CB_RECV_INITIAL_METADATA][0] =
-        op->recv_initial_metadata_ready;
-    s->callback_list[CB_RECV_INITIAL_METADATA][1] = op->on_complete;
-  }
-  if (op->send_initial_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG,
-              "perform_stream_op - send_initial_metadata: on_complete=%p",
-              op->on_complete);
-    }
-    s->num_headers = 0;
-    convert_metadata_to_cronet_headers(op->send_initial_metadata->list.head,
-                                       ct->host, s);
-    s->header_array.count = s->num_headers;
-    s->header_array.capacity = s->num_headers;
-    s->header_array.headers = s->headers;
-    GPR_ASSERT(!s->callback_list[CB_SEND_INITIAL_METADATA][0]);
-    s->callback_list[CB_SEND_INITIAL_METADATA][0] = op->on_complete;
-  }
-  if (op->send_message) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG, "perform_stream_op - send_message: on_complete=%p",
-              op->on_complete);
-    }
-    grpc_byte_stream_next(exec_ctx, op->send_message, &s->slice,
-                          op->send_message->length, NULL);
-    // Check that compression flag is not ON. We don't support compression yet.
-    // TODO (makdharma): add compression support
-    GPR_ASSERT(op->send_message->flags == 0);
-    gpr_slice_buffer_add(&s->write_slice_buffer, s->slice);
-    if (s->cbs == NULL) {
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_create");
-      }
-      s->cbs = cronet_bidirectional_stream_create(ct->engine, s, &callbacks);
-      GPR_ASSERT(s->cbs);
-      s->read_closed = false;
-      s->response_trailers_received = false;
-      s->response_headers_received = false;
-      s->cronet_send_state = CRONET_SEND_IDLE;
-      s->cronet_recv_state = CRONET_RECV_IDLE;
-    }
-    GPR_ASSERT(!s->callback_list[CB_SEND_MESSAGE][0]);
-    s->callback_list[CB_SEND_MESSAGE][0] = op->on_complete;
-    next_send_step(s);
-  }
-  if (op->send_trailing_metadata) {
-    if (grpc_cronet_trace) {
-      gpr_log(GPR_DEBUG,
-              "perform_stream_op - send_trailing_metadata: on_complete=%p",
-              op->on_complete);
-    }
-    GPR_ASSERT(!s->callback_list[CB_SEND_TRAILING_METADATA][0]);
-    s->callback_list[CB_SEND_TRAILING_METADATA][0] = op->on_complete;
-    if (s->cbs) {
-      // Send an "empty" write to the far end to signal that we're done.
-      // This will induce the server to send down trailers.
-      if (grpc_cronet_trace) {
-        gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write");
-      }
-      cronet_bidirectional_stream_write(s->cbs, "abc", 0, true);
+/*
+  TODO (makdharma): Break down this function in smaller chunks for readability.
+*/
+static enum e_op_result execute_stream_op(grpc_exec_ctx *exec_ctx,
+                                          struct op_and_state *oas) {
+  grpc_transport_stream_op *stream_op = &oas->op;
+  struct stream_obj *s = oas->s;
+  struct op_state *stream_state = &s->state;
+  enum e_op_result result = NO_ACTION_POSSIBLE;
+  if (stream_op->send_initial_metadata &&
+      op_can_be_run(stream_op, stream_state, &oas->state,
+                    OP_SEND_INITIAL_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p OP_SEND_INITIAL_METADATA", oas);
+    /* This OP is the beginning. Reset various states */
+    memset(&s->header_array, 0, sizeof(s->header_array));
+    memset(&stream_state->rs, 0, sizeof(stream_state->rs));
+    memset(&stream_state->ws, 0, sizeof(stream_state->ws));
+    memset(stream_state->state_op_done, 0, sizeof(stream_state->state_op_done));
+    memset(stream_state->state_callback_received, 0,
+           sizeof(stream_state->state_callback_received));
+    /* Start new cronet stream. It is destroyed in on_succeeded, on_canceled,
+     * on_failed */
+    GPR_ASSERT(s->cbs == NULL);
+    s->cbs = cronet_bidirectional_stream_create(s->curr_ct.engine, s->curr_gs,
+                                                &cronet_callbacks);
+    CRONET_LOG(GPR_DEBUG, "%p = cronet_bidirectional_stream_create()", s->cbs);
+    char *url;
+    s->header_array.headers = NULL;
+    convert_metadata_to_cronet_headers(
+        stream_op->send_initial_metadata->list.head, s->curr_ct.host, &url,
+        &s->header_array.headers, &s->header_array.count);
+    s->header_array.capacity = s->header_array.count;
+    CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_start(%p, %s)", s->cbs,
+               url);
+    cronet_bidirectional_stream_start(s->cbs, url, 0, "POST", &s->header_array,
+                                      false);
+    stream_state->state_op_done[OP_SEND_INITIAL_METADATA] = true;
+    result = ACTION_TAKEN_WITH_CALLBACK;
+  } else if (stream_op->recv_initial_metadata &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           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_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);
     } else {
-      // We never created a stream. This was probably an empty request.
-      invoke_closing_callback(s);
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_initial_metadata_ready,
+                          GRPC_ERROR_CANCELLED, NULL);
     }
+    stream_state->state_op_done[OP_RECV_INITIAL_METADATA] = true;
+    result = ACTION_TAKEN_NO_CALLBACK;
+  } else if (stream_op->send_message &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_SEND_MESSAGE)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_SEND_MESSAGE", oas);
+    gpr_slice_buffer write_slice_buffer;
+    gpr_slice slice;
+    gpr_slice_buffer_init(&write_slice_buffer);
+    grpc_byte_stream_next(NULL, stream_op->send_message, &slice,
+                          stream_op->send_message->length, NULL);
+    /* Check that compression flag is OFF. We don't support compression yet. */
+    if (stream_op->send_message->flags != 0) {
+      gpr_log(GPR_ERROR, "Compression is not supported");
+      GPR_ASSERT(stream_op->send_message->flags == 0);
+    }
+    gpr_slice_buffer_add(&write_slice_buffer, slice);
+    if (write_slice_buffer.count != 1) {
+      /* Empty request not handled yet */
+      gpr_log(GPR_ERROR, "Empty request is not supported");
+      GPR_ASSERT(write_slice_buffer.count == 1);
+    }
+    if (write_slice_buffer.count > 0) {
+      size_t write_buffer_size;
+      create_grpc_frame(&write_slice_buffer, &stream_state->ws.write_buffer,
+                        &write_buffer_size);
+      CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, %p)",
+                 s->cbs, stream_state->ws.write_buffer);
+      stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
+      cronet_bidirectional_stream_write(s->cbs, stream_state->ws.write_buffer,
+                                        (int)write_buffer_size, false);
+      result = ACTION_TAKEN_WITH_CALLBACK;
+    }
+    stream_state->state_op_done[OP_SEND_MESSAGE] = true;
+    oas->state.state_op_done[OP_SEND_MESSAGE] = true;
+  } else if (stream_op->recv_message &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_RECV_MESSAGE)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_MESSAGE", oas);
+    if (stream_state->state_op_done[OP_CANCEL_ERROR]) {
+      grpc_exec_ctx_sched(exec_ctx, stream_op->recv_message_ready,
+                          GRPC_ERROR_CANCELLED, NULL);
+      stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+    } 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);
+      stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+      oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+    } else if (stream_state->rs.length_field_received == false) {
+      if (stream_state->rs.received_bytes == GRPC_HEADER_SIZE_IN_BYTES &&
+          stream_state->rs.remaining_bytes == 0) {
+        /* Start a read operation for data */
+        stream_state->rs.length_field_received = true;
+        stream_state->rs.length_field = stream_state->rs.remaining_bytes =
+            parse_grpc_header((const uint8_t *)stream_state->rs.read_buffer);
+        CRONET_LOG(GPR_DEBUG, "length field = %d",
+                   stream_state->rs.length_field);
+        if (stream_state->rs.length_field > 0) {
+          stream_state->rs.read_buffer =
+              gpr_malloc((size_t)stream_state->rs.length_field);
+          GPR_ASSERT(stream_state->rs.read_buffer);
+          stream_state->rs.remaining_bytes = stream_state->rs.length_field;
+          stream_state->rs.received_bytes = 0;
+          CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
+          stream_state->state_op_done[OP_READ_REQ_MADE] =
+              true; /* Indicates that at least one read request has been made */
+          cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
+                                           stream_state->rs.remaining_bytes);
+          result = ACTION_TAKEN_WITH_CALLBACK;
+        } else {
+          stream_state->rs.remaining_bytes = 0;
+          CRONET_LOG(GPR_DEBUG, "read operation complete. Empty response.");
+          gpr_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+          grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
+                                        &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);
+          stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+          oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+          result = ACTION_TAKEN_NO_CALLBACK;
+        }
+      } else if (stream_state->rs.remaining_bytes == 0) {
+        /* Start a read operation for first 5 bytes (GRPC header) */
+        stream_state->rs.read_buffer = stream_state->rs.grpc_header_bytes;
+        stream_state->rs.remaining_bytes = GRPC_HEADER_SIZE_IN_BYTES;
+        stream_state->rs.received_bytes = 0;
+        CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_read(%p)", s->cbs);
+        stream_state->state_op_done[OP_READ_REQ_MADE] =
+            true; /* Indicates that at least one read request has been made */
+        cronet_bidirectional_stream_read(s->cbs, stream_state->rs.read_buffer,
+                                         stream_state->rs.remaining_bytes);
+      }
+      result = ACTION_TAKEN_WITH_CALLBACK;
+    } else if (stream_state->rs.remaining_bytes == 0) {
+      CRONET_LOG(GPR_DEBUG, "read operation complete");
+      gpr_slice read_data_slice =
+          gpr_slice_malloc((uint32_t)stream_state->rs.length_field);
+      uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice);
+      memcpy(dst_p, stream_state->rs.read_buffer,
+             (size_t)stream_state->rs.length_field);
+      gpr_slice_buffer_init(&stream_state->rs.read_slice_buffer);
+      gpr_slice_buffer_add(&stream_state->rs.read_slice_buffer,
+                           read_data_slice);
+      grpc_slice_buffer_stream_init(&stream_state->rs.sbs,
+                                    &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);
+      stream_state->state_op_done[OP_RECV_MESSAGE] = true;
+      oas->state.state_op_done[OP_RECV_MESSAGE] = true;
+      /* Clear read state of the stream, so next read op (if it were to come)
+       * will work */
+      stream_state->rs.received_bytes = stream_state->rs.remaining_bytes =
+          stream_state->rs.length_field_received = 0;
+      result = ACTION_TAKEN_NO_CALLBACK;
+    }
+  } else if (stream_op->recv_trailing_metadata &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_RECV_TRAILING_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_RECV_TRAILING_METADATA", oas);
+    if (oas->s->state.rs.trailing_metadata_valid) {
+      grpc_chttp2_incoming_metadata_buffer_publish(
+          &oas->s->state.rs.trailing_metadata,
+          stream_op->recv_trailing_metadata);
+      stream_state->rs.trailing_metadata_valid = false;
+    }
+    stream_state->state_op_done[OP_RECV_TRAILING_METADATA] = true;
+    result = ACTION_TAKEN_NO_CALLBACK;
+  } else if (stream_op->send_trailing_metadata &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_SEND_TRAILING_METADATA)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_SEND_TRAILING_METADATA", oas);
+    CRONET_LOG(GPR_DEBUG, "cronet_bidirectional_stream_write (%p, 0)", s->cbs);
+    stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
+    cronet_bidirectional_stream_write(s->cbs, "", 0, true);
+    stream_state->state_op_done[OP_SEND_TRAILING_METADATA] = true;
+    result = ACTION_TAKEN_WITH_CALLBACK;
+  } else if (stream_op->cancel_error &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_CANCEL_ERROR)) {
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_CANCEL_ERROR", oas);
+    CRONET_LOG(GPR_DEBUG, "W: cronet_bidirectional_stream_cancel(%p)", s->cbs);
+    if (s->cbs) {
+      cronet_bidirectional_stream_cancel(s->cbs);
+    }
+    stream_state->state_op_done[OP_CANCEL_ERROR] = true;
+    result = ACTION_TAKEN_WITH_CALLBACK;
+  } else if (stream_op->on_complete &&
+             op_can_be_run(stream_op, stream_state, &oas->state,
+                           OP_ON_COMPLETE)) {
+    /* All actions in this stream_op are complete. Call the on_complete callback
+     */
+    CRONET_LOG(GPR_DEBUG, "running: %p  OP_ON_COMPLETE", oas);
+    grpc_exec_ctx_sched(exec_ctx, stream_op->on_complete, GRPC_ERROR_NONE,
+                        NULL);
+    oas->state.state_op_done[OP_ON_COMPLETE] = true;
+    oas->done = true;
+    /* reset any send message state, only if this ON_COMPLETE is about a send.
+     */
+    if (stream_op->send_message) {
+      stream_state->state_callback_received[OP_SEND_MESSAGE] = false;
+      stream_state->state_op_done[OP_SEND_MESSAGE] = false;
+    }
+    result = ACTION_TAKEN_NO_CALLBACK;
+    /* If this is the on_complete callback being called for a received message -
+      make a note */
+    if (stream_op->recv_message)
+      stream_state->state_op_done[OP_RECV_MESSAGE_AND_ON_COMPLETE] = true;
+  } else {
+    result = NO_ACTION_POSSIBLE;
   }
+  return result;
 }
 
+/*
+  Functions used by upper layers to access transport functionality.
+*/
+
 static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                        grpc_stream *gs, grpc_stream_refcount *refcount,
                        const void *server_data) {
   stream_obj *s = (stream_obj *)gs;
-  memset(s->callback_list, 0, sizeof(s->callback_list));
+  memset(&s->storage, 0, sizeof(s->storage));
+  s->storage.head = NULL;
+  memset(&s->state, 0, sizeof(s->state));
+  s->curr_op = NULL;
   s->cbs = NULL;
-  gpr_mu_init(&s->recv_mu);
-  s->read_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES);
-  s->write_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES);
-  gpr_slice_buffer_init(&s->write_slice_buffer);
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "cronet_transport - init_stream");
-  }
+  memset(&s->header_array, 0, sizeof(s->header_array));
+  memset(&s->state.rs, 0, sizeof(s->state.rs));
+  memset(&s->state.ws, 0, sizeof(s->state.ws));
+  memset(s->state.state_op_done, 0, sizeof(s->state.state_op_done));
+  memset(s->state.state_callback_received, 0,
+         sizeof(s->state.state_callback_received));
+  gpr_mu_init(&s->mu);
   return 0;
 }
 
-static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                           grpc_stream *gs, void *and_free_memory) {
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "Destroy stream");
-  }
+static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                                   grpc_stream *gs, grpc_pollset *pollset) {}
+
+static void set_pollset_set_do_nothing(grpc_exec_ctx *exec_ctx,
+                                       grpc_transport *gt, grpc_stream *gs,
+                                       grpc_pollset_set *pollset_set) {}
+
+static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                              grpc_stream *gs, grpc_transport_stream_op *op) {
+  CRONET_LOG(GPR_DEBUG, "perform_stream_op");
   stream_obj *s = (stream_obj *)gs;
-  s->cbs = NULL;
-  gpr_free(s->read_buffer);
-  gpr_free(s->write_buffer);
-  gpr_free(s->url);
-  gpr_mu_destroy(&s->recv_mu);
-  if (and_free_memory) {
-    gpr_free(and_free_memory);
-  }
+  s->curr_gs = gs;
+  memcpy(&s->curr_ct, gt, sizeof(grpc_cronet_transport));
+  add_to_storage(s, op);
+  execute_from_storage(s);
 }
 
-static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
-  grpc_cronet_transport *ct = (grpc_cronet_transport *)gt;
-  gpr_free(ct->host);
-  if (grpc_cronet_trace) {
-    gpr_log(GPR_DEBUG, "Destroy transport");
-  }
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                           grpc_stream *gs, void *and_free_memory) {}
+
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {}
+
+static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+  return NULL;
 }
 
+static void perform_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                       grpc_transport_op *op) {}
+
 const grpc_transport_vtable grpc_cronet_vtable = {sizeof(stream_obj),
                                                   "cronet_http",
                                                   init_stream,
                                                   set_pollset_do_nothing,
                                                   set_pollset_set_do_nothing,
                                                   perform_stream_op,
-                                                  NULL,
+                                                  perform_op,
                                                   destroy_stream,
                                                   destroy_transport,
-                                                  NULL};
+                                                  get_peer};
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 653d04f..aec61ee 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -37,6 +37,8 @@
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
 
+// Channel args are intentionally immutable, to avoid the need for locking.
+
 /** Copy the arguments in \a src into a new instance */
 grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src);
 
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 87175d7..98f304f 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -157,12 +157,13 @@
   }
 }
 
-void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
-                          grpc_channel_stack *channel_stack, int initial_refs,
-                          grpc_iomgr_cb_func destroy, void *destroy_arg,
-                          grpc_call_context_element *context,
-                          const void *transport_server_data,
-                          grpc_call_stack *call_stack) {
+grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_stack *channel_stack,
+                                 int initial_refs, grpc_iomgr_cb_func destroy,
+                                 void *destroy_arg,
+                                 grpc_call_context_element *context,
+                                 const void *transport_server_data,
+                                 grpc_call_stack *call_stack) {
   grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
   grpc_call_element_args args;
   size_t count = channel_stack->count;
@@ -178,6 +179,7 @@
               ROUND_UP_TO_ALIGNMENT_SIZE(count * sizeof(grpc_call_element));
 
   /* init per-filter data */
+  grpc_error *first_error = GRPC_ERROR_NONE;
   for (i = 0; i < count; i++) {
     args.call_stack = call_stack;
     args.server_transport_data = transport_server_data;
@@ -185,10 +187,19 @@
     call_elems[i].filter = channel_elems[i].filter;
     call_elems[i].channel_data = channel_elems[i].channel_data;
     call_elems[i].call_data = user_data;
-    call_elems[i].filter->init_call_elem(exec_ctx, &call_elems[i], &args);
+    grpc_error *error =
+        call_elems[i].filter->init_call_elem(exec_ctx, &call_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(call_elems[i].filter->sizeof_call_data);
   }
+  return first_error;
 }
 
 void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -217,7 +228,7 @@
     grpc_polling_entity *pollent) {}
 
 void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
-                             const grpc_call_stats *call_stats,
+                             const grpc_call_final_info *final_info,
                              void *and_free_memory) {
   grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
   size_t count = stack->count;
@@ -225,7 +236,7 @@
 
   /* destroy per-filter data */
   for (i = 0; i < count; i++) {
-    elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], call_stats,
+    elems[i].filter->destroy_call_elem(exec_ctx, &elems[i], final_info,
                                        i == count - 1 ? and_free_memory : NULL);
   }
 }
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index d72c015..6b73cce 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -51,6 +51,10 @@
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/transport/transport.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct grpc_channel_element grpc_channel_element;
 typedef struct grpc_call_element grpc_call_element;
 
@@ -75,9 +79,14 @@
 typedef struct {
   grpc_transport_stream_stats transport_stream_stats;
   gpr_timespec latency; /* From call creating to enqueing of received status */
-  grpc_status_code final_status;
 } grpc_call_stats;
 
+/** Information about the call upon completion. */
+typedef struct {
+  grpc_call_stats stats;
+  grpc_status_code final_status;
+} grpc_call_final_info;
+
 /* Channel filters specify:
    1. the amount of memory needed in the channel & call (via the sizeof_XXX
       members)
@@ -110,8 +119,9 @@
      on a client; if it is non-NULL, then it points to memory owned by the
      transport and is on the server. Most filters want to ignore this
      argument. */
-  void (*init_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                         grpc_call_element_args *args);
+  grpc_error *(*init_call_elem)(grpc_exec_ctx *exec_ctx,
+                                grpc_call_element *elem,
+                                grpc_call_element_args *args);
   void (*set_pollset_or_pollset_set)(grpc_exec_ctx *exec_ctx,
                                      grpc_call_element *elem,
                                      grpc_polling_entity *pollent);
@@ -119,16 +129,17 @@
      The filter does not need to do any chaining.
      The bottom filter of a stack will be passed a non-NULL pointer to
      \a and_free_memory that should be passed to gpr_free when destruction
-     is complete. */
+     is complete. \a final_info contains data about the completed call, mainly
+     for reporting purposes. */
   void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                            const grpc_call_stats *stats,
+                            const grpc_call_final_info *final_info,
                             void *and_free_memory);
 
   /* sizeof(per channel data) */
   size_t sizeof_channel_data;
   /* Initialize per-channel data.
-     elem is initialized at the start of the call, and elem->channel_data is
-     what needs initializing.
+     elem is initialized at the creating of the channel, and elem->channel_data
+     is what needs initializing.
      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 */
@@ -209,12 +220,13 @@
 /* Initialize a call stack given a channel stack. transport_server_data is
    expected to be NULL on a client, or an opaque transport owned pointer on the
    server. */
-void grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
-                          grpc_channel_stack *channel_stack, int initial_refs,
-                          grpc_iomgr_cb_func destroy, void *destroy_arg,
-                          grpc_call_context_element *context,
-                          const void *transport_server_data,
-                          grpc_call_stack *call_stack);
+grpc_error *grpc_call_stack_init(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_stack *channel_stack,
+                                 int initial_refs, grpc_iomgr_cb_func destroy,
+                                 void *destroy_arg,
+                                 grpc_call_context_element *context,
+                                 const void *transport_server_data,
+                                 grpc_call_stack *call_stack);
 /* Set a pollset or a pollset_set for a call stack: must occur before the first
  * op is started */
 void grpc_call_stack_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -243,7 +255,7 @@
 
 /* Destroy a call stack */
 void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
-                             const grpc_call_stats *call_stats,
+                             const grpc_call_final_info *final_info,
                              void *and_free_memory);
 
 /* Ignore set pollset{_set} - used by filters if they don't care about pollsets
@@ -283,4 +295,8 @@
 #define GRPC_CALL_LOG_OP(sev, elem, op) \
   if (grpc_trace_channel) grpc_call_log_op(sev, elem, op)
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H */
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index 0e6bfd9..4a00f7b 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -39,6 +39,10 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /// grpc_channel_stack_builder offers a programmatic interface to selected
 /// and order channel filters
 typedef struct grpc_channel_stack_builder grpc_channel_stack_builder;
@@ -158,4 +162,8 @@
 
 extern int grpc_trace_channel_stack_builder;
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H */
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 32ebe53..134180e 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -256,8 +256,9 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
 
@@ -266,11 +267,14 @@
   calld->has_compression_algorithm = 0;
   grpc_closure_init(&calld->got_slice, got_slice, elem);
   grpc_closure_init(&calld->send_done, send_done, elem);
+
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   gpr_slice_buffer_destroy(&calld->slices);
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 0a7d27a..918379c 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -81,16 +81,16 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
-  int r;
-
-  r = grpc_transport_init_stream(
+  int r = grpc_transport_init_stream(
       exec_ctx, chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld),
       &args->call_stack->refcount, args->server_transport_data);
-  GPR_ASSERT(r == 0);
+  return r == 0 ? GRPC_ERROR_NONE
+                : GRPC_ERROR_CREATE("transport stream initialization failed");
 }
 
 static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -104,7 +104,7 @@
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats,
+                              const grpc_call_final_info *final_info,
                               void *and_free_memory) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
diff --git a/src/core/lib/channel/context.h b/src/core/lib/channel/context.h
index c50e842..071c5f6 100644
--- a/src/core/lib/channel/context.h
+++ b/src/core/lib/channel/context.h
@@ -34,10 +34,19 @@
 #ifndef GRPC_CORE_LIB_CHANNEL_CONTEXT_H
 #define GRPC_CORE_LIB_CHANNEL_CONTEXT_H
 
-/* Call object context pointers */
+/// Call object context pointers.
+
+/// Call context is represented as an array of \a grpc_call_context_elements.
+/// This enum represents the indexes into the array, where each index
+/// contains a different type of value.
 typedef enum {
+  /// Value is either a \a grpc_client_security_context or a
+  /// \a grpc_server_security_context.
   GRPC_CONTEXT_SECURITY = 0,
+
+  /// Value is a \a census_context.
   GRPC_CONTEXT_TRACING,
+
   GRPC_CONTEXT_COUNT
 } grpc_context_index;
 
diff --git a/src/core/lib/channel/handshaker.c b/src/core/lib/channel/handshaker.c
new file mode 100644
index 0000000..c0979f5
--- /dev/null
+++ b/src/core/lib/channel/handshaker.c
@@ -0,0 +1,203 @@
+/*
+ *
+ * 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 <string.h>
+
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/log.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/handshaker.h"
+
+//
+// grpc_handshaker
+//
+
+void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable,
+                          grpc_handshaker* handshaker) {
+  handshaker->vtable = vtable;
+}
+
+void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
+                             grpc_handshaker* handshaker) {
+  handshaker->vtable->destroy(exec_ctx, handshaker);
+}
+
+void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
+                              grpc_handshaker* handshaker) {
+  handshaker->vtable->shutdown(exec_ctx, handshaker);
+}
+
+void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
+                                  grpc_handshaker* handshaker,
+                                  grpc_endpoint* endpoint,
+                                  grpc_channel_args* args,
+                                  gpr_slice_buffer* read_buffer,
+                                  gpr_timespec deadline,
+                                  grpc_tcp_server_acceptor* acceptor,
+                                  grpc_handshaker_done_cb cb, void* user_data) {
+  handshaker->vtable->do_handshake(exec_ctx, handshaker, endpoint, args,
+                                   read_buffer, deadline, acceptor, cb,
+                                   user_data);
+}
+
+//
+// grpc_handshake_manager
+//
+
+// State used while chaining handshakers.
+struct grpc_handshaker_state {
+  // The index of the handshaker to invoke next.
+  size_t index;
+  // The deadline for all handshakers.
+  gpr_timespec deadline;
+  // The acceptor to call the handshakers with.
+  grpc_tcp_server_acceptor* acceptor;
+  // The final callback and user_data to invoke after the last handshaker.
+  grpc_handshaker_done_cb final_cb;
+  void* final_user_data;
+};
+
+struct grpc_handshake_manager {
+  // An array of handshakers added via grpc_handshake_manager_add().
+  size_t count;
+  grpc_handshaker** handshakers;
+  // State used while chaining handshakers.
+  struct grpc_handshaker_state* state;
+};
+
+grpc_handshake_manager* grpc_handshake_manager_create() {
+  grpc_handshake_manager* mgr = gpr_malloc(sizeof(grpc_handshake_manager));
+  memset(mgr, 0, sizeof(*mgr));
+  return mgr;
+}
+
+static bool is_power_of_2(size_t n) { return (n & (n - 1)) == 0; }
+
+void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
+                                grpc_handshaker* handshaker) {
+  // To avoid allocating memory for each handshaker we add, we double
+  // the number of elements every time we need more.
+  size_t realloc_count = 0;
+  if (mgr->count == 0) {
+    realloc_count = 2;
+  } else if (mgr->count >= 2 && is_power_of_2(mgr->count)) {
+    realloc_count = mgr->count * 2;
+  }
+  if (realloc_count > 0) {
+    mgr->handshakers =
+        gpr_realloc(mgr->handshakers, realloc_count * sizeof(grpc_handshaker*));
+  }
+  mgr->handshakers[mgr->count++] = handshaker;
+}
+
+void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
+                                    grpc_handshake_manager* mgr) {
+  for (size_t i = 0; i < mgr->count; ++i) {
+    grpc_handshaker_destroy(exec_ctx, mgr->handshakers[i]);
+  }
+  gpr_free(mgr->handshakers);
+  gpr_free(mgr);
+}
+
+void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
+                                     grpc_handshake_manager* mgr) {
+  for (size_t i = 0; i < mgr->count; ++i) {
+    grpc_handshaker_shutdown(exec_ctx, mgr->handshakers[i]);
+  }
+  if (mgr->state != NULL) {
+    gpr_free(mgr->state);
+    mgr->state = NULL;
+  }
+}
+
+// A function used as the handshaker-done callback when chaining
+// handshakers together.
+static void call_next_handshaker(grpc_exec_ctx* exec_ctx,
+                                 grpc_endpoint* endpoint,
+                                 grpc_channel_args* args,
+                                 gpr_slice_buffer* read_buffer, void* user_data,
+                                 grpc_error* error) {
+  grpc_handshake_manager* mgr = user_data;
+  GPR_ASSERT(mgr->state != NULL);
+  GPR_ASSERT(mgr->state->index < mgr->count);
+  // If we got an error, skip all remaining handshakers and invoke the
+  // caller-supplied callback immediately.
+  if (error != GRPC_ERROR_NONE) {
+    mgr->state->final_cb(exec_ctx, endpoint, args, read_buffer,
+                         mgr->state->final_user_data, error);
+    return;
+  }
+  grpc_handshaker_done_cb cb = call_next_handshaker;
+  // If this is the last handshaker, use the caller-supplied callback
+  // and user_data instead of chaining back to this function again.
+  if (mgr->state->index == mgr->count - 1) {
+    cb = mgr->state->final_cb;
+    user_data = mgr->state->final_user_data;
+  }
+  // Invoke handshaker.
+  grpc_handshaker_do_handshake(
+      exec_ctx, mgr->handshakers[mgr->state->index], endpoint, args,
+      read_buffer, mgr->state->deadline, mgr->state->acceptor, cb, user_data);
+  ++mgr->state->index;
+  // If this is the last handshaker, clean up state.
+  if (mgr->state->index == mgr->count) {
+    gpr_free(mgr->state);
+    mgr->state = NULL;
+  }
+}
+
+void grpc_handshake_manager_do_handshake(
+    grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
+    grpc_endpoint* endpoint, const grpc_channel_args* args,
+    gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
+    grpc_handshaker_done_cb cb, void* user_data) {
+  grpc_channel_args* args_copy = grpc_channel_args_copy(args);
+  gpr_slice_buffer* read_buffer = malloc(sizeof(*read_buffer));
+  gpr_slice_buffer_init(read_buffer);
+  if (mgr->count == 0) {
+    // No handshakers registered, so we just immediately call the done
+    // callback with the passed-in endpoint.
+    cb(exec_ctx, endpoint, args_copy, read_buffer, user_data, GRPC_ERROR_NONE);
+  } else {
+    GPR_ASSERT(mgr->state == NULL);
+    mgr->state = gpr_malloc(sizeof(struct grpc_handshaker_state));
+    memset(mgr->state, 0, sizeof(*mgr->state));
+    mgr->state->deadline = deadline;
+    mgr->state->acceptor = acceptor;
+    mgr->state->final_cb = cb;
+    mgr->state->final_user_data = user_data;
+    call_next_handshaker(exec_ctx, endpoint, args_copy, read_buffer, mgr,
+                         GRPC_ERROR_NONE);
+  }
+}
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
new file mode 100644
index 0000000..b276f60
--- /dev/null
+++ b/src/core/lib/channel/handshaker.h
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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_H
+#define GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/impl/codegen/time.h>
+#include <grpc/support/slice_buffer.h>
+
+#include "src/core/lib/iomgr/closure.h"
+#include "src/core/lib/iomgr/endpoint.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/iomgr/tcp_server.h"
+
+/// Handshakers are used to perform initial handshakes on a connection
+/// before the client sends the initial request.  Some examples of what
+/// a handshaker can be used for includes support for HTTP CONNECT on
+/// the client side and various types of security initialization.
+///
+/// In general, handshakers should be used via a handshake manager.
+
+///
+/// grpc_handshaker
+///
+
+typedef struct grpc_handshaker grpc_handshaker;
+
+/// Callback type invoked when a handshaker is done.
+/// Takes ownership of \a args and \a read_buffer.
+typedef void (*grpc_handshaker_done_cb)(grpc_exec_ctx* exec_ctx,
+                                        grpc_endpoint* endpoint,
+                                        grpc_channel_args* args,
+                                        gpr_slice_buffer* read_buffer,
+                                        void* user_data, grpc_error* error);
+
+struct grpc_handshaker_vtable {
+  /// Destroys the handshaker.
+  void (*destroy)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
+
+  /// Shuts down the handshaker (e.g., to clean up when the operation is
+  /// aborted in the middle).
+  void (*shutdown)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker);
+
+  /// Performs handshaking.  When finished, calls \a cb with \a user_data.
+  /// Takes ownership of \a args.
+  /// Takes ownership of \a read_buffer, which contains leftover bytes read
+  /// from the endpoint by the previous handshaker.
+  /// \a acceptor will be NULL for client-side handshakers.
+  void (*do_handshake)(grpc_exec_ctx* exec_ctx, grpc_handshaker* handshaker,
+                       grpc_endpoint* endpoint, grpc_channel_args* args,
+                       gpr_slice_buffer* read_buffer, gpr_timespec deadline,
+                       grpc_tcp_server_acceptor* acceptor,
+                       grpc_handshaker_done_cb cb, void* user_data);
+};
+
+/// Base struct.  To subclass, make this the first member of the
+/// implementation struct.
+struct grpc_handshaker {
+  const struct grpc_handshaker_vtable* vtable;
+};
+
+/// Called by concrete implementations to initialize the base struct.
+void grpc_handshaker_init(const struct grpc_handshaker_vtable* vtable,
+                          grpc_handshaker* handshaker);
+
+/// Convenient wrappers for invoking methods via the vtable.
+/// These probably do not need to be called from anywhere but
+/// grpc_handshake_manager.
+void grpc_handshaker_destroy(grpc_exec_ctx* exec_ctx,
+                             grpc_handshaker* handshaker);
+void grpc_handshaker_shutdown(grpc_exec_ctx* exec_ctx,
+                              grpc_handshaker* handshaker);
+void grpc_handshaker_do_handshake(grpc_exec_ctx* exec_ctx,
+                                  grpc_handshaker* handshaker,
+                                  grpc_endpoint* endpoint,
+                                  grpc_channel_args* args,
+                                  gpr_slice_buffer* read_buffer,
+                                  gpr_timespec deadline,
+                                  grpc_tcp_server_acceptor* acceptor,
+                                  grpc_handshaker_done_cb cb, void* user_data);
+
+///
+/// grpc_handshake_manager
+///
+
+typedef struct grpc_handshake_manager grpc_handshake_manager;
+
+/// Creates a new handshake manager.  Caller takes ownership.
+grpc_handshake_manager* grpc_handshake_manager_create();
+
+/// Adds a handshaker to the handshake manager.
+/// Takes ownership of \a handshaker.
+void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
+                                grpc_handshaker* handshaker);
+
+/// Destroys the handshake manager.
+void grpc_handshake_manager_destroy(grpc_exec_ctx* exec_ctx,
+                                    grpc_handshake_manager* mgr);
+
+/// Shuts down the handshake manager (e.g., to clean up when the operation is
+/// aborted in the middle).
+/// The caller must still call grpc_handshake_manager_destroy() after
+/// calling this function.
+void grpc_handshake_manager_shutdown(grpc_exec_ctx* exec_ctx,
+                                     grpc_handshake_manager* mgr);
+
+/// Invokes handshakers in the order they were added.
+/// Does NOT take ownership of \a args.  Instead, makes a copy before
+/// invoking the first handshaker.
+/// \a acceptor will be NULL for client-side handshakers.
+/// Invokes \a cb with \a user_data after either a handshaker fails or
+/// all handshakers have completed successfully.
+void grpc_handshake_manager_do_handshake(
+    grpc_exec_ctx* exec_ctx, grpc_handshake_manager* mgr,
+    grpc_endpoint* endpoint, const grpc_channel_args* args,
+    gpr_timespec deadline, grpc_tcp_server_acceptor* acceptor,
+    grpc_handshaker_done_cb cb, void* user_data);
+
+#endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 8057e251..a7a775c 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -175,16 +175,19 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   calld->on_done_recv = NULL;
   grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {}
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {}
 
 static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
   unsigned i;
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index d0beebd..5ce51f9 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -224,18 +224,21 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   /* initialize members */
   memset(calld, 0, sizeof(*calld));
   grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {}
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {}
 
 /* Constructor for channel_data */
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index a57d93b..0006e80 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -61,6 +61,7 @@
 static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
                                      grpc_channel_security_connector *sc,
                                      grpc_endpoint *nonsecure_endpoint,
+                                     gpr_slice_buffer *read_buffer,
                                      gpr_timespec deadline,
                                      grpc_security_handshake_done_cb cb,
                                      void *user_data) {
@@ -69,6 +70,7 @@
   tsi_result result = TSI_OK;
   tsi_handshaker *handshaker;
   if (c->handshaker_factory == NULL) {
+    gpr_free(read_buffer);
     cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
     return;
   }
@@ -77,10 +79,12 @@
   if (result != TSI_OK) {
     gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
             tsi_result_to_string(result));
+    gpr_free(read_buffer);
     cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
   } else {
     grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
-                               nonsecure_endpoint, deadline, cb, user_data);
+                               nonsecure_endpoint, read_buffer, deadline, cb,
+                               user_data);
   }
 }
 
@@ -183,7 +187,7 @@
                  pem_root_certs, pem_root_certs_size, host, &sc) ==
              GRPC_SECURITY_OK);
   grpc_channel_security_connector_do_handshake(
-      exec_ctx, sc, tcp, deadline, on_secure_transport_setup_done, c);
+      exec_ctx, sc, tcp, NULL, deadline, on_secure_transport_setup_done, c);
   GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
 }
 
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 13f898e..bc77812 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -171,6 +171,8 @@
                                 gpr_timespec value) GRPC_MUST_USE_RESULT;
 grpc_error *grpc_error_set_str(grpc_error *src, grpc_error_strs which,
                                const char *value) GRPC_MUST_USE_RESULT;
+/// Returns NULL if the specified string is not set.
+/// Caller does NOT own return value.
 const char *grpc_error_get_str(grpc_error *error, grpc_error_strs which);
 /// Add a child error: an error that is believed to have contributed to this
 /// error occurring. Allows root causing high level errors from lower level
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 6a63c4d..02bcbaa 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -42,6 +42,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <poll.h>
+#include <pthread.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/epoll.h>
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index 4b593f4..16a5e30 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -844,6 +844,11 @@
   *worker_hdl = &worker;
   grpc_error *error = GRPC_ERROR_NONE;
 
+  /* Avoid malloc for small number of elements. */
+  enum { inline_elements = 96 };
+  struct pollfd pollfd_space[inline_elements];
+  struct grpc_fd_watcher watcher_space[inline_elements];
+
   /* pollset->mu already held */
   int added_worker = 0;
   int locked = 1;
@@ -899,15 +904,23 @@
       int r;
       size_t i, fd_count;
       nfds_t pfd_count;
-      /* TODO(ctiller): inline some elements to avoid an allocation */
       grpc_fd_watcher *watchers;
       struct pollfd *pfds;
 
       timeout = poll_deadline_to_millis_timeout(deadline, now);
-      /* TODO(ctiller): perform just one malloc here if we exceed the inline
-       * case */
-      pfds = gpr_malloc(sizeof(*pfds) * (pollset->fd_count + 2));
-      watchers = gpr_malloc(sizeof(*watchers) * (pollset->fd_count + 2));
+
+      if (pollset->fd_count + 2 <= inline_elements) {
+        pfds = pollfd_space;
+        watchers = watcher_space;
+      } else {
+        /* Allocate one buffer to hold both pfds and watchers arrays */
+        const size_t pfd_size = sizeof(*pfds) * (pollset->fd_count + 2);
+        const size_t watch_size = sizeof(*watchers) * (pollset->fd_count + 2);
+        void *buf = gpr_malloc(pfd_size + watch_size);
+        pfds = buf;
+        watchers = (void *)((char *)buf + pfd_size);
+      }
+
       fd_count = 0;
       pfd_count = 2;
       pfds[0].fd = GRPC_WAKEUP_FD_GET_READ_FD(&grpc_global_wakeup_fd);
@@ -974,8 +987,11 @@
         }
       }
 
-      gpr_free(pfds);
-      gpr_free(watchers);
+      if (pfds != pollfd_space) {
+        /* pfds and watchers are in the same memory block pointed to by pfds */
+        gpr_free(pfds);
+      }
+
       GPR_TIMER_END("maybe_work_and_unlock", 0);
       locked = 0;
     } else {
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index ec21e03..974d5ae 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -284,7 +284,7 @@
 }
 
 /* returns true if done, false if pending; if returning true, *error is set */
-#define MAX_WRITE_IOVEC 1024
+#define MAX_WRITE_IOVEC 1000
 static bool tcp_flush(grpc_tcp *tcp, grpc_error **error) {
   struct msghdr msg;
   struct iovec iov[MAX_WRITE_IOVEC];
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
index 875a6ca..5a25d39 100644
--- a/src/core/lib/iomgr/tcp_server.h
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -105,4 +105,8 @@
    a call (exec_ctx!=NULL) to shutdown_complete. */
 void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s);
 
+/* Shutdown the fds of listeners. */
+void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
+                                        grpc_tcp_server *s);
+
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_H */
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index 425634d..2d3f6cf 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -90,10 +90,12 @@
   grpc_closure read_closure;
   grpc_closure destroyed_closure;
   struct grpc_tcp_listener *next;
-  /* When we add a listener, more than one can be created, mainly because of
-     IPv6. A sibling will still be in the normal list, but will be flagged
-     as such. Any action, such as ref or unref, will affect all of the
-     siblings in the list. */
+  /* sibling is a linked list of all listeners for a given port. add_port and
+     clone_port place all new listeners in the same sibling list. A member of
+     the 'sibling' list is also a member of the 'next' list. The head of each
+     sibling list has is_sibling==0, and subsequent members of sibling lists
+     have is_sibling==1. is_sibling allows separate sibling lists to be
+     identified while iterating through 'next'. */
   struct grpc_tcp_listener *sibling;
   int is_sibling;
 };
@@ -308,7 +310,7 @@
 
   GPR_ASSERT(fd >= 0);
 
-  if (so_reuseport) {
+  if (so_reuseport && !grpc_is_unix_socket(addr)) {
     err = grpc_set_socket_reuse_port(fd, 1);
     if (err != GRPC_ERROR_NONE) goto error;
   }
@@ -482,6 +484,9 @@
   return err;
 }
 
+/* Insert count new listeners after listener. Every new listener will have the
+   same listen address as listener (SO_REUSEPORT must be enabled). Every new
+   listener is a sibling of listener. */
 static grpc_error *clone_port(grpc_tcp_listener *listener, unsigned count) {
   grpc_tcp_listener *sp = NULL;
   char *addr_str;
@@ -508,6 +513,11 @@
     sp = gpr_malloc(sizeof(grpc_tcp_listener));
     sp->next = listener->next;
     listener->next = sp;
+    /* sp (the new listener) is a sibling of 'listener' (the original
+       listener). */
+    sp->is_sibling = 1;
+    sp->sibling = listener->sibling;
+    listener->sibling = sp;
     sp->server = listener->server;
     sp->fd = fd;
     sp->emfd = grpc_fd_create(fd, name);
@@ -516,8 +526,6 @@
     sp->port = port;
     sp->port_index = listener->port_index;
     sp->fd_index = listener->fd_index + count - i;
-    sp->is_sibling = 1;
-    sp->sibling = listener->is_sibling ? listener->sibling : listener;
     GPR_ASSERT(sp->emfd);
     while (listener->server->tail->next != NULL) {
       listener->server->tail = listener->server->tail->next;
@@ -687,7 +695,8 @@
   s->pollset_count = pollset_count;
   sp = s->head;
   while (sp != NULL) {
-    if (s->so_reuseport && pollset_count > 1) {
+    if (s->so_reuseport && !grpc_is_unix_socket(&sp->addr.sockaddr) &&
+        pollset_count > 1) {
       GPR_ASSERT(GRPC_LOG_IF_ERROR(
           "clone_port", clone_port(sp, (unsigned)(pollset_count - 1))));
       for (i = 0; i < pollset_count; i++) {
@@ -743,4 +752,17 @@
   }
 }
 
+void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
+                                        grpc_tcp_server *s) {
+  gpr_mu_lock(&s->mu);
+  /* shutdown all fd's */
+  if (s->active_ports) {
+    grpc_tcp_listener *sp;
+    for (sp = s->head; sp; sp = sp->next) {
+      grpc_fd_shutdown(exec_ctx, sp->emfd);
+    }
+  }
+  gpr_mu_unlock(&s->mu);
+}
+
 #endif
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index 7b09667..1b125e7 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -540,4 +540,7 @@
   gpr_mu_unlock(&s->mu);
 }
 
+void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx *exec_ctx,
+                                        grpc_tcp_server *s) {}
+
 #endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/lib/json/json_reader.c b/src/core/lib/json/json_reader.c
index bc04bcc..5b42ca5 100644
--- a/src/core/lib/json/json_reader.c
+++ b/src/core/lib/json/json_reader.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -171,8 +171,9 @@
         switch (reader->state) {
           case GRPC_JSON_STATE_OBJECT_KEY_STRING:
           case GRPC_JSON_STATE_VALUE_STRING:
-            if (reader->unicode_high_surrogate != 0)
+            if (reader->unicode_high_surrogate != 0) {
               return GRPC_JSON_PARSE_ERROR;
+            }
             json_reader_string_add_char(reader, c);
             break;
 
@@ -289,8 +290,9 @@
             break;
 
           case GRPC_JSON_STATE_OBJECT_KEY_STRING:
-            if (reader->unicode_high_surrogate != 0)
+            if (reader->unicode_high_surrogate != 0) {
               return GRPC_JSON_PARSE_ERROR;
+            }
             if (c == '"') {
               reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
               json_reader_set_key(reader);
@@ -302,8 +304,9 @@
             break;
 
           case GRPC_JSON_STATE_VALUE_STRING:
-            if (reader->unicode_high_surrogate != 0)
+            if (reader->unicode_high_surrogate != 0) {
               return GRPC_JSON_PARSE_ERROR;
+            }
             if (c == '"') {
               reader->state = GRPC_JSON_STATE_VALUE_END;
               json_reader_set_string(reader);
@@ -383,8 +386,9 @@
             } else {
               reader->state = GRPC_JSON_STATE_VALUE_STRING;
             }
-            if (reader->unicode_high_surrogate && c != 'u')
+            if (reader->unicode_high_surrogate && c != 'u') {
               return GRPC_JSON_PARSE_ERROR;
+            }
             switch (c) {
               case '"':
               case '/':
diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h
index ef0c06b..4e7666d 100644
--- a/src/core/lib/security/context/security_context.h
+++ b/src/core/lib/security/context/security_context.h
@@ -37,6 +37,10 @@
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/security/credentials/credentials.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* --- grpc_auth_context ---
 
    High level authentication context object. Can optionally be chained. */
@@ -111,4 +115,8 @@
 grpc_auth_context *grpc_find_auth_context_in_args(
     const grpc_channel_args *args);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_SECURITY_CONTEXT_SECURITY_CONTEXT_H */
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index ed7929a..2a1bf4d 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -267,10 +267,12 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   memset(calld, 0, sizeof(*calld));
+  return GRPC_ERROR_NONE;
 }
 
 static void set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
@@ -282,7 +284,8 @@
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {
   call_data *calld = elem->call_data;
   grpc_call_credentials_unref(calld->creds);
   if (calld->host != NULL) {
diff --git a/src/core/lib/security/transport/handshake.c b/src/core/lib/security/transport/handshake.c
index b374ca7..fbeec31 100644
--- a/src/core/lib/security/transport/handshake.c
+++ b/src/core/lib/security/transport/handshake.c
@@ -325,8 +325,9 @@
 void grpc_do_security_handshake(
     grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
     grpc_security_connector *connector, bool is_client_side,
-    grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
-    grpc_security_handshake_done_cb cb, void *user_data) {
+    grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
+    gpr_timespec deadline, grpc_security_handshake_done_cb cb,
+    void *user_data) {
   grpc_security_connector_handshake_list *handshake_node;
   grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake));
   memset(h, 0, sizeof(grpc_security_handshake));
@@ -346,6 +347,10 @@
   gpr_slice_buffer_init(&h->left_overs);
   gpr_slice_buffer_init(&h->outgoing);
   gpr_slice_buffer_init(&h->incoming);
+  if (read_buffer != NULL) {
+    gpr_slice_buffer_move_into(read_buffer, &h->incoming);
+    gpr_free(read_buffer);
+  }
   if (!is_client_side) {
     grpc_server_security_connector *server_connector =
         (grpc_server_security_connector *)connector;
@@ -357,8 +362,9 @@
     gpr_mu_unlock(&server_connector->mu);
   }
   send_handshake_bytes_to_peer(exec_ctx, h);
-  grpc_timer_init(exec_ctx, &h->timer, deadline, on_timeout, h,
-                  gpr_now(deadline.clock_type));
+  grpc_timer_init(exec_ctx, &h->timer,
+                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+                  on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC));
 }
 
 void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/transport/handshake.h b/src/core/lib/security/transport/handshake.h
index c0906dd..53092f5 100644
--- a/src/core/lib/security/transport/handshake.h
+++ b/src/core/lib/security/transport/handshake.h
@@ -37,12 +37,13 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/security/transport/security_connector.h"
 
-/* Calls the callback upon completion. Takes owership of handshaker. */
+/* Calls the callback upon completion. Takes owership of handshaker and
+ * read_buffer. */
 void grpc_do_security_handshake(
     grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker,
     grpc_security_connector *connector, bool is_client_side,
-    grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
-    grpc_security_handshake_done_cb cb, void *user_data);
+    grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
+    gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
 
 void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake);
 
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index bc50f9d..0169ccd 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -128,7 +128,7 @@
 
 static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
                          grpc_error *error) {
-  if (false && grpc_trace_secure_endpoint) {
+  if (grpc_trace_secure_endpoint) {
     size_t i;
     for (i = 0; i < ep->read_buffer->count; i++) {
       char *data = gpr_dump_slice(ep->read_buffer->slices[i],
@@ -256,7 +256,7 @@
 
   gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
 
-  if (false && grpc_trace_secure_endpoint) {
+  if (grpc_trace_secure_endpoint) {
     for (i = 0; i < slices->count; i++) {
       char *data =
           gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index f0ee677..0eca46e 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -127,25 +127,29 @@
 
 void grpc_channel_security_connector_do_handshake(
     grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
-    grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
-    grpc_security_handshake_done_cb cb, void *user_data) {
+    grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
+    gpr_timespec deadline, grpc_security_handshake_done_cb cb,
+    void *user_data) {
   if (sc == NULL || nonsecure_endpoint == NULL) {
+    gpr_free(read_buffer);
     cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
   } else {
-    sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, deadline, cb, user_data);
+    sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, read_buffer, deadline,
+                     cb, user_data);
   }
 }
 
 void grpc_server_security_connector_do_handshake(
     grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
     grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
-    gpr_timespec deadline, grpc_security_handshake_done_cb cb,
-    void *user_data) {
+    gpr_slice_buffer *read_buffer, gpr_timespec deadline,
+    grpc_security_handshake_done_cb cb, void *user_data) {
   if (sc == NULL || nonsecure_endpoint == NULL) {
+    gpr_free(read_buffer);
     cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
   } else {
-    sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, deadline, cb,
-                     user_data);
+    sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, read_buffer,
+                     deadline, cb, user_data);
   }
 }
 
@@ -312,23 +316,23 @@
 static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
                                       grpc_channel_security_connector *sc,
                                       grpc_endpoint *nonsecure_endpoint,
+                                      gpr_slice_buffer *read_buffer,
                                       gpr_timespec deadline,
                                       grpc_security_handshake_done_cb cb,
                                       void *user_data) {
   grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
-                             true, nonsecure_endpoint, deadline, cb, user_data);
+                             true, nonsecure_endpoint, read_buffer, deadline,
+                             cb, user_data);
 }
 
-static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx,
-                                     grpc_server_security_connector *sc,
-                                     grpc_tcp_server_acceptor *acceptor,
-                                     grpc_endpoint *nonsecure_endpoint,
-                                     gpr_timespec deadline,
-                                     grpc_security_handshake_done_cb cb,
-                                     void *user_data) {
+static void fake_server_do_handshake(
+    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
+    grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
+    gpr_slice_buffer *read_buffer, gpr_timespec deadline,
+    grpc_security_handshake_done_cb cb, void *user_data) {
   grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
-                             false, nonsecure_endpoint, deadline, cb,
-                             user_data);
+                             false, nonsecure_endpoint, read_buffer, deadline,
+                             cb, user_data);
 }
 
 static grpc_security_connector_vtable fake_channel_vtable = {
@@ -418,6 +422,7 @@
 static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
                                      grpc_channel_security_connector *sc,
                                      grpc_endpoint *nonsecure_endpoint,
+                                     gpr_slice_buffer *read_buffer,
                                      gpr_timespec deadline,
                                      grpc_security_handshake_done_cb cb,
                                      void *user_data) {
@@ -430,30 +435,32 @@
                                         : c->target_name,
       &handshaker);
   if (status != GRPC_SECURITY_OK) {
+    gpr_free(read_buffer);
     cb(exec_ctx, user_data, status, NULL, NULL);
   } else {
     grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
-                               nonsecure_endpoint, deadline, cb, user_data);
+                               nonsecure_endpoint, read_buffer, deadline, cb,
+                               user_data);
   }
 }
 
-static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
-                                    grpc_server_security_connector *sc,
-                                    grpc_tcp_server_acceptor *acceptor,
-                                    grpc_endpoint *nonsecure_endpoint,
-                                    gpr_timespec deadline,
-                                    grpc_security_handshake_done_cb cb,
-                                    void *user_data) {
+static void ssl_server_do_handshake(
+    grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
+    grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
+    gpr_slice_buffer *read_buffer, gpr_timespec deadline,
+    grpc_security_handshake_done_cb cb, void *user_data) {
   grpc_ssl_server_security_connector *c =
       (grpc_ssl_server_security_connector *)sc;
   tsi_handshaker *handshaker;
   grpc_security_status status =
       ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
   if (status != GRPC_SECURITY_OK) {
+    gpr_free(read_buffer);
     cb(exec_ctx, user_data, status, NULL, NULL);
   } else {
     grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
-                               nonsecure_endpoint, deadline, cb, user_data);
+                               nonsecure_endpoint, read_buffer, deadline, cb,
+                               user_data);
   }
 }
 
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index c2ddf5e..0b5b44b 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -143,7 +143,8 @@
                           grpc_security_call_host_check_cb cb, void *user_data);
   void (*do_handshake)(grpc_exec_ctx *exec_ctx,
                        grpc_channel_security_connector *sc,
-                       grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
+                       grpc_endpoint *nonsecure_endpoint,
+                       gpr_slice_buffer *read_buffer, gpr_timespec deadline,
                        grpc_security_handshake_done_cb cb, void *user_data);
 };
 
@@ -156,8 +157,8 @@
 /* Handshake. */
 void grpc_channel_security_connector_do_handshake(
     grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
-    grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
-    grpc_security_handshake_done_cb cb, void *user_data);
+    grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer,
+    gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
 
 /* --- server_security_connector object. ---
 
@@ -174,14 +175,16 @@
   void (*do_handshake)(grpc_exec_ctx *exec_ctx,
                        grpc_server_security_connector *sc,
                        grpc_tcp_server_acceptor *acceptor,
-                       grpc_endpoint *nonsecure_endpoint, gpr_timespec deadline,
+                       grpc_endpoint *nonsecure_endpoint,
+                       gpr_slice_buffer *read_buffer, gpr_timespec deadline,
                        grpc_security_handshake_done_cb cb, void *user_data);
 };
 
 void grpc_server_security_connector_do_handshake(
     grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
     grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
-    gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data);
+    gpr_slice_buffer *read_buffer, gpr_timespec deadline,
+    grpc_security_handshake_done_cb cb, void *user_data);
 
 void grpc_server_security_connector_shutdown(
     grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector);
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index 12e789b..def16c8 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -199,8 +199,9 @@
 }
 
 /* Constructor for call_data */
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
@@ -222,11 +223,14 @@
   args->context[GRPC_CONTEXT_SECURITY].value = server_ctx;
   args->context[GRPC_CONTEXT_SECURITY].destroy =
       grpc_server_security_context_destroy;
+
+  return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {}
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {}
 
 /* Constructor for channel_data */
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/support/log_linux.c b/src/core/lib/support/log_linux.c
index 508fae4..299b377 100644
--- a/src/core/lib/support/log_linux.c
+++ b/src/core/lib/support/log_linux.c
@@ -47,7 +47,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
-#include <linux/unistd.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
diff --git a/src/core/lib/support/slice.c b/src/core/lib/support/slice.c
index b9a7c77..8a2c0a9 100644
--- a/src/core/lib/support/slice.c
+++ b/src/core/lib/support/slice.c
@@ -94,14 +94,16 @@
   }
 }
 
-gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
+gpr_slice gpr_slice_new_with_user_data(void *p, size_t len,
+                                       void (*destroy)(void *),
+                                       void *user_data) {
   gpr_slice slice;
   new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
   gpr_ref_init(&rc->refs, 1);
   rc->rc.ref = new_slice_ref;
   rc->rc.unref = new_slice_unref;
   rc->user_destroy = destroy;
-  rc->user_data = p;
+  rc->user_data = user_data;
 
   slice.refcount = &rc->rc;
   slice.data.refcounted.bytes = p;
@@ -109,6 +111,11 @@
   return slice;
 }
 
+gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
+  /* Pass "p" to *destroy when the slice is no longer needed. */
+  return gpr_slice_new_with_user_data(p, len, destroy, p);
+}
+
 /* gpr_slice_new_with_len support structures - we create a refcount object
    extended with the user provided data pointer & destroy function */
 typedef struct new_with_len_slice_refcount {
diff --git a/src/core/lib/support/time.c b/src/core/lib/support/time.c
index 57f8331..5a7d043 100644
--- a/src/core/lib/support/time.c
+++ b/src/core/lib/support/time.c
@@ -80,103 +80,67 @@
   return out;
 }
 
-/* TODO(ctiller): consider merging _nanos, _micros, _millis into a single
-   function for maintainability. Similarly for _seconds, _minutes, and _hours */
+static gpr_timespec to_seconds_from_sub_second_time(int64_t time_in_units,
+                                                    int64_t units_per_sec,
+                                                    gpr_clock_type type) {
+  gpr_timespec out;
+  if (time_in_units == INT64_MAX) {
+    out = gpr_inf_future(type);
+  } else if (time_in_units == INT64_MIN) {
+    out = gpr_inf_past(type);
+  } else {
+    if (time_in_units >= 0) {
+      out.tv_sec = time_in_units / units_per_sec;
+    } else {
+      out.tv_sec = (-((units_per_sec - 1) - (time_in_units + units_per_sec)) /
+                    units_per_sec) -
+                   1;
+    }
+    out.tv_nsec = (int32_t)((time_in_units - out.tv_sec * units_per_sec) *
+                            GPR_NS_PER_SEC / units_per_sec);
+    out.clock_type = type;
+  }
+  return out;
+}
+
+static gpr_timespec to_seconds_from_above_second_time(int64_t time_in_units,
+                                                      int64_t secs_per_unit,
+                                                      gpr_clock_type type) {
+  gpr_timespec out;
+  if (time_in_units >= INT64_MAX / secs_per_unit) {
+    out = gpr_inf_future(type);
+  } else if (time_in_units <= INT64_MIN / secs_per_unit) {
+    out = gpr_inf_past(type);
+  } else {
+    out.tv_sec = time_in_units * secs_per_unit;
+    out.tv_nsec = 0;
+    out.clock_type = type;
+  }
+  return out;
+}
 
 gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (ns == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (ns == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else if (ns >= 0) {
-    result.tv_sec = ns / GPR_NS_PER_SEC;
-    result.tv_nsec = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC);
-  } else {
-    /* Calculation carefully formulated to avoid any possible under/overflow. */
-    result.tv_sec = (-(999999999 - (ns + GPR_NS_PER_SEC)) / GPR_NS_PER_SEC) - 1;
-    result.tv_nsec = (int32_t)(ns - result.tv_sec * GPR_NS_PER_SEC);
-  }
-  return result;
+  return to_seconds_from_sub_second_time(ns, GPR_NS_PER_SEC, type);
 }
 
 gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (us == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (us == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else if (us >= 0) {
-    result.tv_sec = us / 1000000;
-    result.tv_nsec = (int32_t)((us - result.tv_sec * 1000000) * 1000);
-  } else {
-    /* Calculation carefully formulated to avoid any possible under/overflow. */
-    result.tv_sec = (-(999999 - (us + 1000000)) / 1000000) - 1;
-    result.tv_nsec = (int32_t)((us - result.tv_sec * 1000000) * 1000);
-  }
-  return result;
+  return to_seconds_from_sub_second_time(us, GPR_US_PER_SEC, type);
 }
 
 gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (ms == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (ms == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else if (ms >= 0) {
-    result.tv_sec = ms / 1000;
-    result.tv_nsec = (int32_t)((ms - result.tv_sec * 1000) * 1000000);
-  } else {
-    /* Calculation carefully formulated to avoid any possible under/overflow. */
-    result.tv_sec = (-(999 - (ms + 1000)) / 1000) - 1;
-    result.tv_nsec = (int32_t)((ms - result.tv_sec * 1000) * 1000000);
-  }
-  return result;
+  return to_seconds_from_sub_second_time(ms, GPR_MS_PER_SEC, type);
 }
 
 gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (s == INT64_MAX) {
-    result = gpr_inf_future(type);
-  } else if (s == INT64_MIN) {
-    result = gpr_inf_past(type);
-  } else {
-    result.tv_sec = s;
-    result.tv_nsec = 0;
-  }
-  return result;
+  return to_seconds_from_sub_second_time(s, 1, type);
 }
 
 gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (m >= INT64_MAX / 60) {
-    result = gpr_inf_future(type);
-  } else if (m <= INT64_MIN / 60) {
-    result = gpr_inf_past(type);
-  } else {
-    result.tv_sec = m * 60;
-    result.tv_nsec = 0;
-  }
-  return result;
+  return to_seconds_from_above_second_time(m, 60, type);
 }
 
 gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
-  gpr_timespec result;
-  result.clock_type = type;
-  if (h >= INT64_MAX / 3600) {
-    result = gpr_inf_future(type);
-  } else if (h <= INT64_MIN / 3600) {
-    result = gpr_inf_past(type);
-  } else {
-    result.tv_sec = h * 3600;
-    result.tv_nsec = 0;
-  }
-  return result;
+  return to_seconds_from_above_second_time(h, 3600, type);
 }
 
 gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b) {
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index fc9df76..7726811 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -154,8 +154,9 @@
   /* Received call statuses from various sources */
   received_status status[STATUS_SOURCE_COUNT];
 
-  /* Call stats: only valid after trailing metadata received */
-  grpc_call_stats stats;
+  /* Call data useful used for reporting. Only valid after the call has
+   * completed */
+  grpc_call_final_info final_info;
 
   /* Compression algorithm for *incoming* data */
   grpc_compression_algorithm incoming_compression_algorithm;
@@ -263,9 +264,19 @@
       gpr_convert_clock_type(send_deadline, GPR_CLOCK_MONOTONIC);
   GRPC_CHANNEL_INTERNAL_REF(channel, "call");
   /* initial refcount dropped by grpc_call_destroy */
-  grpc_call_stack_init(&exec_ctx, channel_stack, 1, destroy_call, call,
-                       call->context, server_transport_data,
-                       CALL_STACK_FROM_CALL(call));
+  grpc_error *error = grpc_call_stack_init(
+      &exec_ctx, channel_stack, 1, destroy_call, call, call->context,
+      server_transport_data, CALL_STACK_FROM_CALL(call));
+  if (error != GRPC_ERROR_NONE) {
+    intptr_t status;
+    if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status))
+      status = GRPC_STATUS_UNKNOWN;
+    const char *error_str =
+        grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION);
+    close_with_status(&exec_ctx, call, (grpc_status_code)status,
+                      error_str == NULL ? "unknown error" : error_str);
+    GRPC_ERROR_UNREF(error);
+  }
   if (cq != NULL) {
     GPR_ASSERT(
         pollset_set_alternative == NULL &&
@@ -361,6 +372,25 @@
   GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
 }
 
+static void get_final_status(grpc_call *call,
+                             void (*set_value)(grpc_status_code code,
+                                               void *user_data),
+                             void *set_value_user_data) {
+  int i;
+  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
+    if (call->status[i].is_set) {
+      set_value(call->status[i].code, set_value_user_data);
+      return;
+    }
+  }
+  if (call->is_client) {
+    set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
+  } else {
+    set_value(GRPC_STATUS_OK, set_value_user_data);
+  }
+}
+
+static void set_status_value_directly(grpc_status_code status, void *dest);
 static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
                          grpc_error *error) {
   size_t i;
@@ -392,7 +422,11 @@
     GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
   }
   grpc_channel *channel = c->channel;
-  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->stats, c);
+
+  get_final_status(call, set_status_value_directly,
+                   &c->final_info.final_status);
+
+  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), &c->final_info, c);
   GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
   GPR_TIMER_END("destroy_call", 0);
 }
@@ -414,24 +448,6 @@
   }
 }
 
-static void get_final_status(grpc_call *call,
-                             void (*set_value)(grpc_status_code code,
-                                               void *user_data),
-                             void *set_value_user_data) {
-  int i;
-  for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
-    if (call->status[i].is_set) {
-      set_value(call->status[i].code, set_value_user_data);
-      return;
-    }
-  }
-  if (call->is_client) {
-    set_value(GRPC_STATUS_UNKNOWN, set_value_user_data);
-  } else {
-    set_value(GRPC_STATUS_OK, set_value_user_data);
-  }
-}
-
 static void set_status_from_error(grpc_call *call, status_source source,
                                   grpc_error *error) {
   intptr_t status;
@@ -1361,6 +1377,9 @@
   int num_completion_callbacks_needed = 1;
   grpc_call_error error = GRPC_CALL_OK;
 
+  // sent_initial_metadata guards against variable reuse.
+  grpc_metadata compression_md;
+
   GPR_TIMER_BEGIN("grpc_call_start_batch", 0);
 
   GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
@@ -1406,8 +1425,7 @@
           goto done_with_error;
         }
         /* process compression level */
-        grpc_metadata compression_md;
-        memset(&compression_md, 0, sizeof(grpc_metadata));
+        memset(&compression_md, 0, sizeof(compression_md));
         size_t additional_metadata_count = 0;
         grpc_compression_level effective_compression_level;
         bool level_set = false;
@@ -1608,7 +1626,8 @@
         bctl->recv_final_op = 1;
         stream_op.recv_trailing_metadata =
             &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        stream_op.collect_stats = &call->stats.transport_stream_stats;
+        stream_op.collect_stats =
+            &call->final_info.stats.transport_stream_stats;
         break;
       case GRPC_OP_RECV_CLOSE_ON_SERVER:
         /* Flag validation: currently allow no flags */
@@ -1630,7 +1649,8 @@
         bctl->recv_final_op = 1;
         stream_op.recv_trailing_metadata =
             &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        stream_op.collect_stats = &call->stats.transport_stream_stats;
+        stream_op.collect_stats =
+            &call->final_info.stats.transport_stream_stats;
         break;
     }
   }
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 7eff7b8..4c62974 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -42,6 +42,14 @@
                                   grpc_channel_stack_type channel_stack_type,
                                   grpc_transport *optional_transport);
 
+/** Create a call given a grpc_channel, in order to call \a method.
+    Progress is tied to activity on \a pollset_set. The returned call object is
+    meant to be used with \a grpc_call_start_batch_and_execute, which relies on
+    callbacks to signal completions. \a method and \a host need
+    only live through the invocation of this function. If \a parent_call is
+    non-NULL, it must be a server-side call. It will be used to propagate
+    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,
diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h
index 3a18a61..b53f2ae 100644
--- a/src/core/lib/surface/channel_init.h
+++ b/src/core/lib/surface/channel_init.h
@@ -40,6 +40,10 @@
 
 #define GRPC_CHANNEL_INIT_BUILTIN_PRIORITY 10000
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /// This module provides a way for plugins (and the grpc core library itself)
 /// to register mutators for channel stacks.
 /// It also provides a universal entry path to run those mutators to build
@@ -84,4 +88,8 @@
                                     grpc_channel_stack_builder *builder,
                                     grpc_channel_stack_type type);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H */
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 5ea4cba..19b7836 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -107,11 +107,14 @@
   GRPC_ERROR_UNREF(op->disconnect_with_error);
 }
 
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {}
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
+  return GRPC_ERROR_NONE;
+}
 
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats,
+                              const grpc_call_final_info *final_info,
                               void *and_free_memory) {
   gpr_free(and_free_memory);
 }
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 2f108af..64afcec 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -272,7 +272,7 @@
 }
 
 static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
-                          int send_goaway, grpc_error *send_disconnect) {
+                          bool send_goaway, grpc_error *send_disconnect) {
   grpc_transport_op op;
   struct shutdown_cleanup_args *sc;
   grpc_channel_element *elem;
@@ -293,7 +293,7 @@
 
 static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx,
                                          channel_broadcaster *cb,
-                                         int send_goaway,
+                                         bool send_goaway,
                                          grpc_error *force_disconnect) {
   size_t i;
 
@@ -856,8 +856,9 @@
   }
 }
 
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   memset(calld, 0, sizeof(call_data));
@@ -869,10 +870,12 @@
                     server_on_recv_initial_metadata, elem);
 
   server_ref(chand->server);
+  return GRPC_ERROR_NONE;
 }
 
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
 
@@ -1249,7 +1252,8 @@
     l->destroy(&exec_ctx, server, l->arg, &l->destroy_done);
   }
 
-  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 1, 0);
+  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, true /* send_goaway */,
+                               GRPC_ERROR_NONE);
 
 done:
   grpc_exec_ctx_finish(&exec_ctx);
@@ -1265,7 +1269,7 @@
   channel_broadcaster_init(server, &broadcaster);
   gpr_mu_unlock(&server->mu_global);
 
-  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, 0,
+  channel_broadcaster_shutdown(&exec_ctx, &broadcaster, false /* send_goaway */,
                                GRPC_ERROR_CREATE("Cancelling all calls"));
   grpc_exec_ctx_finish(&exec_ctx);
 }
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 9463436..1942075 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -36,4 +36,4 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "1.0.1-pre1"; }
+const char *grpc_version_string(void) { return "1.1.0-dev"; }
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
index 95519a9..e64dce6 100644
--- a/src/core/lib/transport/byte_stream.h
+++ b/src/core/lib/transport/byte_stream.h
@@ -59,13 +59,9 @@
  * on_complete will not be called), 0 if the bytes will be available
  * asynchronously.
  *
- * on entry, *remaining can be set as a hint as to the maximum number
+ * max_size_hint can be set as a hint as to the maximum number
  * of bytes that would be acceptable to read.
  *
- * fills *buffer, *length, *remaining with the bytes, length of bytes
- * and length of data remaining to be read before either returning 1
- * or calling on_complete.
- *
  * once a slice is returned into *slice, it is owned by the caller.
  */
 int grpc_byte_stream_next(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 6d82f4d..2b0921c 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -37,6 +37,10 @@
 #include <grpc/support/slice.h>
 #include <grpc/support/useful.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* This file provides a mechanism for tracking metadata through the grpc stack.
    It's not intended for consumption outside of the library.
 
@@ -164,4 +168,8 @@
 extern gpr_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(
     gpr_slice input);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_H */
diff --git a/src/core/lib/transport/metadata_batch.c b/src/core/lib/transport/metadata_batch.c
index e4398ab..84b5a74 100644
--- a/src/core/lib/transport/metadata_batch.c
+++ b/src/core/lib/transport/metadata_batch.c
@@ -33,6 +33,7 @@
 
 #include "src/core/lib/transport/metadata_batch.h"
 
+#include <stdbool.h>
 #include <string.h>
 
 #include <grpc/support/alloc.h>
@@ -187,7 +188,7 @@
   grpc_metadata_batch_filter(batch, no_metadata_for_you, NULL);
 }
 
-int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
+bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch) {
   return batch->list.head == NULL &&
          gpr_time_cmp(gpr_inf_future(batch->deadline.clock_type),
                       batch->deadline) == 0;
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 7af823f..0424b4d 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -34,12 +34,18 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
 #define GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H
 
+#include <stdbool.h>
+
 #include <grpc/grpc.h>
 #include <grpc/support/port_platform.h>
 #include <grpc/support/slice.h>
 #include <grpc/support/time.h>
 #include "src/core/lib/transport/metadata.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct grpc_linked_mdelem {
   grpc_mdelem *md;
   struct grpc_linked_mdelem *next;
@@ -64,7 +70,7 @@
 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);
-int grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
+bool grpc_metadata_batch_is_empty(grpc_metadata_batch *batch);
 
 /* Returns the transport size of the batch. */
 size_t grpc_metadata_batch_size(grpc_metadata_batch *batch);
@@ -125,4 +131,8 @@
   } while (0)
 #endif
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H */
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
index c5f16e5..8f3e5b5 100644
--- a/src/core/lib/transport/static_metadata.c
+++ b/src/core/lib/transport/static_metadata.c
@@ -45,21 +45,21 @@
 
 grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
 uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 4, 8, 6, 2, 4, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
-    {11, 35, 10, 35, 12, 35, 12, 49, 13, 35, 14, 35, 15, 35, 16, 35, 17, 35,
-     19, 35, 20, 35, 21, 35, 24, 35, 25, 35, 26, 35, 27, 35, 28, 35, 29, 35,
-     30, 18, 30, 35, 31, 35, 32, 35, 36, 35, 37, 35, 38, 35, 39, 35, 42, 33,
-     42, 34, 42, 48, 42, 53, 42, 54, 42, 55, 42, 56, 43, 33, 43, 48, 43, 53,
-     46, 0,  46, 1,  46, 2,  50, 35, 57, 35, 58, 35, 59, 35, 60, 35, 61, 35,
-     62, 35, 63, 35, 64, 35, 65, 35, 66, 35, 67, 40, 67, 69, 67, 72, 68, 80,
-     68, 81, 70, 35, 71, 35, 73, 35, 74, 35, 75, 35, 76, 35, 77, 41, 77, 51,
-     77, 52, 78, 35, 79, 35, 82, 3,  82, 4,  82, 5,  82, 6,  82, 7,  82, 8,
-     82, 9,  83, 35, 84, 85, 86, 35, 87, 35, 88, 35, 89, 35, 90, 35};
+    {11, 33, 10, 33, 12, 33, 12, 49, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
+     19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33,
+     28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31,
+     40, 32, 40, 48, 40, 53, 40, 54, 40, 55, 40, 56, 42, 31, 42, 48, 42, 53,
+     45, 0,  45, 1,  45, 2,  50, 33, 57, 33, 58, 33, 59, 33, 60, 33, 61, 33,
+     62, 33, 63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 38, 68, 70, 68, 73,
+     69, 81, 69, 82, 71, 33, 72, 33, 74, 33, 75, 33, 76, 33, 77, 33, 78, 39,
+     78, 51, 78, 52, 79, 33, 80, 33, 83, 3,  83, 4,  83, 5,  83, 6,  83, 7,
+     83, 8,  83, 9,  84, 33, 85, 86, 87, 33, 88, 33, 89, 33, 90, 33, 91, 33};
 
 const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
     "0",
@@ -84,8 +84,6 @@
     ":authority",
     "authorization",
     "cache-control",
-    "census-bin",
-    "census-binary-bin",
     "content-disposition",
     "content-encoding",
     "content-language",
@@ -105,11 +103,13 @@
     "GET",
     "grpc",
     "grpc-accept-encoding",
+    "grpc-census-bin",
     "grpc-encoding",
     "grpc-internal-encoding-request",
     "grpc-message",
     "grpc-status",
     "grpc-timeout",
+    "grpc-tracing-bin",
     "gzip",
     "gzip, deflate",
     "host",
@@ -126,7 +126,8 @@
     "if-unmodified-since",
     "last-modified",
     "link",
-    "load-reporting",
+    "load-reporting-initial",
+    "load-reporting-trailing",
     "location",
     "max-forwards",
     ":method",
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index 5ff0d2f..b51baca 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -44,7 +44,7 @@
 
 #include "src/core/lib/transport/metadata.h"
 
-#define GRPC_STATIC_MDSTR_COUNT 91
+#define GRPC_STATIC_MDSTR_COUNT 92
 extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
 /* "0" */
 #define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
@@ -90,58 +90,58 @@
 #define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
 /* "cache-control" */
 #define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
-/* "census-bin" */
-#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[22])
-/* "census-binary-bin" */
-#define GRPC_MDSTR_CENSUS_BINARY_BIN (&grpc_static_mdstr_table[23])
 /* "content-disposition" */
-#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24])
+#define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[22])
 /* "content-encoding" */
-#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[25])
+#define GRPC_MDSTR_CONTENT_ENCODING (&grpc_static_mdstr_table[23])
 /* "content-language" */
-#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[26])
+#define GRPC_MDSTR_CONTENT_LANGUAGE (&grpc_static_mdstr_table[24])
 /* "content-length" */
-#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[27])
+#define GRPC_MDSTR_CONTENT_LENGTH (&grpc_static_mdstr_table[25])
 /* "content-location" */
-#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[28])
+#define GRPC_MDSTR_CONTENT_LOCATION (&grpc_static_mdstr_table[26])
 /* "content-range" */
-#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[29])
+#define GRPC_MDSTR_CONTENT_RANGE (&grpc_static_mdstr_table[27])
 /* "content-type" */
-#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[30])
+#define GRPC_MDSTR_CONTENT_TYPE (&grpc_static_mdstr_table[28])
 /* "cookie" */
-#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[31])
+#define GRPC_MDSTR_COOKIE (&grpc_static_mdstr_table[29])
 /* "date" */
-#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[32])
+#define GRPC_MDSTR_DATE (&grpc_static_mdstr_table[30])
 /* "deflate" */
-#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[33])
+#define GRPC_MDSTR_DEFLATE (&grpc_static_mdstr_table[31])
 /* "deflate,gzip" */
-#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[34])
+#define GRPC_MDSTR_DEFLATE_COMMA_GZIP (&grpc_static_mdstr_table[32])
 /* "" */
-#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[35])
+#define GRPC_MDSTR_EMPTY (&grpc_static_mdstr_table[33])
 /* "etag" */
-#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[36])
+#define GRPC_MDSTR_ETAG (&grpc_static_mdstr_table[34])
 /* "expect" */
-#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[37])
+#define GRPC_MDSTR_EXPECT (&grpc_static_mdstr_table[35])
 /* "expires" */
-#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[38])
+#define GRPC_MDSTR_EXPIRES (&grpc_static_mdstr_table[36])
 /* "from" */
-#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[39])
+#define GRPC_MDSTR_FROM (&grpc_static_mdstr_table[37])
 /* "GET" */
-#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[40])
+#define GRPC_MDSTR_GET (&grpc_static_mdstr_table[38])
 /* "grpc" */
-#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[41])
+#define GRPC_MDSTR_GRPC (&grpc_static_mdstr_table[39])
 /* "grpc-accept-encoding" */
-#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[42])
+#define GRPC_MDSTR_GRPC_ACCEPT_ENCODING (&grpc_static_mdstr_table[40])
+/* "grpc-census-bin" */
+#define GRPC_MDSTR_GRPC_CENSUS_BIN (&grpc_static_mdstr_table[41])
 /* "grpc-encoding" */
-#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[43])
+#define GRPC_MDSTR_GRPC_ENCODING (&grpc_static_mdstr_table[42])
 /* "grpc-internal-encoding-request" */
-#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[44])
+#define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[43])
 /* "grpc-message" */
-#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[45])
+#define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[44])
 /* "grpc-status" */
-#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
+#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[45])
 /* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
+#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[46])
+/* "grpc-tracing-bin" */
+#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[47])
 /* "gzip" */
 #define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48])
 /* "gzip, deflate" */
@@ -175,62 +175,64 @@
 #define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62])
 /* "link" */
 #define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63])
-/* "load-reporting" */
-#define GRPC_MDSTR_LOAD_REPORTING (&grpc_static_mdstr_table[64])
+/* "load-reporting-initial" */
+#define GRPC_MDSTR_LOAD_REPORTING_INITIAL (&grpc_static_mdstr_table[64])
+/* "load-reporting-trailing" */
+#define GRPC_MDSTR_LOAD_REPORTING_TRAILING (&grpc_static_mdstr_table[65])
 /* "location" */
-#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[65])
+#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[66])
 /* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[66])
+#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[67])
 /* ":method" */
-#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[67])
+#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[68])
 /* ":path" */
-#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[68])
+#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[69])
 /* "POST" */
-#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[69])
+#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[70])
 /* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[70])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[71])
 /* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[71])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[72])
 /* "PUT" */
-#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[72])
+#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[73])
 /* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[73])
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[74])
 /* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[74])
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[75])
 /* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[75])
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[76])
 /* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[76])
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[77])
 /* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[77])
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[78])
 /* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[78])
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[79])
 /* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[79])
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[80])
 /* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[80])
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[81])
 /* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[81])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[82])
 /* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[82])
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[83])
 /* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[83])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[84])
 /* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[84])
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[85])
 /* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[85])
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[86])
 /* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[86])
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[87])
 /* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[87])
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[88])
 /* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[88])
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[89])
 /* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[89])
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[90])
 /* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[90])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[91])
 
-#define GRPC_STATIC_MDELEM_COUNT 80
+#define GRPC_STATIC_MDELEM_COUNT 81
 extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
 extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];
 /* "accept-charset": "" */
@@ -335,73 +337,76 @@
 #define GRPC_MDELEM_LAST_MODIFIED_EMPTY (&grpc_static_mdelem_table[45])
 /* "link": "" */
 #define GRPC_MDELEM_LINK_EMPTY (&grpc_static_mdelem_table[46])
-/* "load-reporting": "" */
-#define GRPC_MDELEM_LOAD_REPORTING_EMPTY (&grpc_static_mdelem_table[47])
+/* "load-reporting-initial": "" */
+#define GRPC_MDELEM_LOAD_REPORTING_INITIAL_EMPTY (&grpc_static_mdelem_table[47])
+/* "load-reporting-trailing": "" */
+#define GRPC_MDELEM_LOAD_REPORTING_TRAILING_EMPTY \
+  (&grpc_static_mdelem_table[48])
 /* "location": "" */
-#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[48])
+#define GRPC_MDELEM_LOCATION_EMPTY (&grpc_static_mdelem_table[49])
 /* "max-forwards": "" */
-#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[49])
+#define GRPC_MDELEM_MAX_FORWARDS_EMPTY (&grpc_static_mdelem_table[50])
 /* ":method": "GET" */
-#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[50])
+#define GRPC_MDELEM_METHOD_GET (&grpc_static_mdelem_table[51])
 /* ":method": "POST" */
-#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[51])
+#define GRPC_MDELEM_METHOD_POST (&grpc_static_mdelem_table[52])
 /* ":method": "PUT" */
-#define GRPC_MDELEM_METHOD_PUT (&grpc_static_mdelem_table[52])
+#define GRPC_MDELEM_METHOD_PUT (&grpc_static_mdelem_table[53])
 /* ":path": "/" */
-#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[53])
+#define GRPC_MDELEM_PATH_SLASH (&grpc_static_mdelem_table[54])
 /* ":path": "/index.html" */
-#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[54])
+#define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML (&grpc_static_mdelem_table[55])
 /* "proxy-authenticate": "" */
-#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[55])
+#define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[56])
 /* "proxy-authorization": "" */
-#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[56])
+#define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY (&grpc_static_mdelem_table[57])
 /* "range": "" */
-#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[57])
+#define GRPC_MDELEM_RANGE_EMPTY (&grpc_static_mdelem_table[58])
 /* "referer": "" */
-#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[58])
+#define GRPC_MDELEM_REFERER_EMPTY (&grpc_static_mdelem_table[59])
 /* "refresh": "" */
-#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[59])
+#define GRPC_MDELEM_REFRESH_EMPTY (&grpc_static_mdelem_table[60])
 /* "retry-after": "" */
-#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[60])
+#define GRPC_MDELEM_RETRY_AFTER_EMPTY (&grpc_static_mdelem_table[61])
 /* ":scheme": "grpc" */
-#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[61])
+#define GRPC_MDELEM_SCHEME_GRPC (&grpc_static_mdelem_table[62])
 /* ":scheme": "http" */
-#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[62])
+#define GRPC_MDELEM_SCHEME_HTTP (&grpc_static_mdelem_table[63])
 /* ":scheme": "https" */
-#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[63])
+#define GRPC_MDELEM_SCHEME_HTTPS (&grpc_static_mdelem_table[64])
 /* "server": "" */
-#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[64])
+#define GRPC_MDELEM_SERVER_EMPTY (&grpc_static_mdelem_table[65])
 /* "set-cookie": "" */
-#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[65])
+#define GRPC_MDELEM_SET_COOKIE_EMPTY (&grpc_static_mdelem_table[66])
 /* ":status": "200" */
-#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[66])
+#define GRPC_MDELEM_STATUS_200 (&grpc_static_mdelem_table[67])
 /* ":status": "204" */
-#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[67])
+#define GRPC_MDELEM_STATUS_204 (&grpc_static_mdelem_table[68])
 /* ":status": "206" */
-#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[68])
+#define GRPC_MDELEM_STATUS_206 (&grpc_static_mdelem_table[69])
 /* ":status": "304" */
-#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[69])
+#define GRPC_MDELEM_STATUS_304 (&grpc_static_mdelem_table[70])
 /* ":status": "400" */
-#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[70])
+#define GRPC_MDELEM_STATUS_400 (&grpc_static_mdelem_table[71])
 /* ":status": "404" */
-#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[71])
+#define GRPC_MDELEM_STATUS_404 (&grpc_static_mdelem_table[72])
 /* ":status": "500" */
-#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[72])
+#define GRPC_MDELEM_STATUS_500 (&grpc_static_mdelem_table[73])
 /* "strict-transport-security": "" */
 #define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \
-  (&grpc_static_mdelem_table[73])
+  (&grpc_static_mdelem_table[74])
 /* "te": "trailers" */
-#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[74])
+#define GRPC_MDELEM_TE_TRAILERS (&grpc_static_mdelem_table[75])
 /* "transfer-encoding": "" */
-#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[75])
+#define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY (&grpc_static_mdelem_table[76])
 /* "user-agent": "" */
-#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[76])
+#define GRPC_MDELEM_USER_AGENT_EMPTY (&grpc_static_mdelem_table[77])
 /* "vary": "" */
-#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[77])
+#define GRPC_MDELEM_VARY_EMPTY (&grpc_static_mdelem_table[78])
 /* "via": "" */
-#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[78])
+#define GRPC_MDELEM_VIA_EMPTY (&grpc_static_mdelem_table[79])
 /* "www-authenticate": "" */
-#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[79])
+#define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY (&grpc_static_mdelem_table[80])
 
 extern const uint8_t
     grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2];
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.c b/src/core/lib/transport/timeout_encoding.c
similarity index 95%
rename from src/core/ext/transport/chttp2/transport/timeout_encoding.c
rename to src/core/lib/transport/timeout_encoding.c
index b7f7912..b58ebbd 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.c
+++ b/src/core/lib/transport/timeout_encoding.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/lib/transport/timeout_encoding.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -117,7 +117,7 @@
   }
 }
 
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer) {
+void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer) {
   if (timeout.tv_sec < 0) {
     enc_tiny(buffer);
   } else if (timeout.tv_sec == 0) {
@@ -136,7 +136,7 @@
   return *p == 0;
 }
 
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
+int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout) {
   int32_t x = 0;
   const uint8_t *p = (const uint8_t *)buffer;
   int have_digit = 0;
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/src/core/lib/transport/timeout_encoding.h
similarity index 77%
rename from src/core/ext/transport/chttp2/transport/timeout_encoding.h
rename to src/core/lib/transport/timeout_encoding.h
index df2324c..92f02f6 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/src/core/lib/transport/timeout_encoding.h
@@ -31,17 +31,17 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#ifndef GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H
+#define GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H
 
 #include <grpc/support/time.h>
 #include "src/core/lib/support/string.h"
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+#define GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
+/* Encode/decode timeouts to the GRPC over HTTP/2 format;
    encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+void grpc_http2_encode_timeout(gpr_timespec timeout, char *buffer);
+int grpc_http2_decode_timeout(const char *buffer, gpr_timespec *timeout);
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+#endif /* GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H */
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 08c0a23..1705e6e 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -43,6 +43,10 @@
 #include "src/core/lib/transport/byte_stream.h"
 #include "src/core/lib/transport/metadata_batch.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* forward declarations */
 typedef struct grpc_transport grpc_transport;
 
@@ -138,7 +142,7 @@
   /** If != GRPC_ERROR_NONE, cancel this stream */
   grpc_error *cancel_error;
 
-  /** If != GRPC_ERROR, send grpc-status, grpc-message, and close this
+  /** If != GRPC_ERROR_NONE, send grpc-status, grpc-message, and close this
       stream for both reading and writing */
   grpc_error *close_error;
 
@@ -158,7 +162,7 @@
   /** should we send a goaway?
       after a goaway is sent, once there are no more active calls on
       the transport, the transport should disconnect */
-  int send_goaway;
+  bool send_goaway;
   /** what should the goaway contain? */
   grpc_status_code goaway_status;
   gpr_slice *goaway_message;
@@ -268,4 +272,8 @@
 char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
                               grpc_transport *transport);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/plugin_registry/grpc_plugin_registry.c b/src/core/plugin_registry/grpc_plugin_registry.c
index 905cd59..7a7a9ce 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_plugin_registry.c
@@ -37,6 +37,8 @@
 extern void grpc_chttp2_plugin_shutdown(void);
 extern void grpc_client_config_init(void);
 extern void grpc_client_config_shutdown(void);
+extern void grpc_lb_policy_grpclb_init(void);
+extern void grpc_lb_policy_grpclb_shutdown(void);
 extern void grpc_lb_policy_pick_first_init(void);
 extern void grpc_lb_policy_pick_first_shutdown(void);
 extern void grpc_lb_policy_round_robin_init(void);
@@ -55,6 +57,8 @@
                        grpc_chttp2_plugin_shutdown);
   grpc_register_plugin(grpc_client_config_init,
                        grpc_client_config_shutdown);
+  grpc_register_plugin(grpc_lb_policy_grpclb_init,
+                       grpc_lb_policy_grpclb_shutdown);
   grpc_register_plugin(grpc_lb_policy_pick_first_init,
                        grpc_lb_policy_pick_first_shutdown);
   grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
index 7995078..ad4ddf0 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
@@ -43,6 +43,8 @@
 extern void grpc_resolver_sockaddr_shutdown(void);
 extern void grpc_load_reporting_plugin_init(void);
 extern void grpc_load_reporting_plugin_shutdown(void);
+extern void grpc_lb_policy_grpclb_init(void);
+extern void grpc_lb_policy_grpclb_shutdown(void);
 extern void grpc_lb_policy_pick_first_init(void);
 extern void grpc_lb_policy_pick_first_shutdown(void);
 extern void grpc_lb_policy_round_robin_init(void);
@@ -61,6 +63,8 @@
                        grpc_resolver_sockaddr_shutdown);
   grpc_register_plugin(grpc_load_reporting_plugin_init,
                        grpc_load_reporting_plugin_shutdown);
+  grpc_register_plugin(grpc_lb_policy_grpclb_init,
+                       grpc_lb_policy_grpclb_shutdown);
   grpc_register_plugin(grpc_lb_policy_pick_first_init,
                        grpc_lb_policy_pick_first_shutdown);
   grpc_register_plugin(grpc_lb_policy_round_robin_init,
diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc
new file mode 100644
index 0000000..25cd49c
--- /dev/null
+++ b/src/cpp/common/channel_filter.cc
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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 <string.h>
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/cpp/common/channel_filter.h"
+
+namespace grpc {
+
+// MetadataBatch
+
+grpc_linked_mdelem *MetadataBatch::AddMetadata(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());
+  grpc_metadata_batch_link_head(batch_, storage);
+  return storage;
+}
+
+// ChannelData
+
+void ChannelData::StartTransportOp(grpc_exec_ctx *exec_ctx,
+                                   grpc_channel_element *elem,
+                                   TransportOp *op) {
+  grpc_channel_next_op(exec_ctx, elem, op->op());
+}
+
+// CallData
+
+void CallData::StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
+                                      grpc_call_element *elem,
+                                      TransportStreamOp *op) {
+  grpc_call_next_op(exec_ctx, elem, op->op());
+}
+
+void CallData::SetPollsetOrPollsetSet(grpc_exec_ctx *exec_ctx,
+                                      grpc_call_element *elem,
+                                      grpc_polling_entity *pollent) {
+  grpc_call_stack_ignore_set_pollset_or_pollset_set(exec_ctx, elem, pollent);
+}
+
+char *CallData::GetPeer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+  return grpc_call_next_get_peer(exec_ctx, elem);
+}
+
+// internal code used by RegisterChannelFilter()
+
+namespace internal {
+
+// Note: Implicitly initialized to nullptr due to static lifetime.
+std::vector<FilterRecord> *channel_filters;
+
+namespace {
+
+bool MaybeAddFilter(grpc_channel_stack_builder *builder, void *arg) {
+  const FilterRecord &filter = *(FilterRecord *)arg;
+  if (filter.include_filter) {
+    const grpc_channel_args *args =
+        grpc_channel_stack_builder_get_channel_arguments(builder);
+    if (!filter.include_filter(*args)) return true;
+  }
+  return grpc_channel_stack_builder_prepend_filter(builder, &filter.filter,
+                                                   nullptr, nullptr);
+}
+
+}  // namespace
+
+void ChannelFilterPluginInit() {
+  for (size_t i = 0; i < channel_filters->size(); ++i) {
+    FilterRecord &filter = (*channel_filters)[i];
+    grpc_channel_init_register_stage(filter.stack_type, filter.priority,
+                                     MaybeAddFilter, (void *)&filter);
+  }
+}
+
+void ChannelFilterPluginShutdown() {}
+
+}  // namespace internal
+
+}  // namespace grpc
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
new file mode 100644
index 0000000..3fbacd8
--- /dev/null
+++ b/src/cpp/common/channel_filter.h
@@ -0,0 +1,386 @@
+/*
+ *
+ * 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 GRPCXX_CHANNEL_FILTER_H
+#define GRPCXX_CHANNEL_FILTER_H
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc/census.h>
+#include <grpc/grpc.h>
+#include <grpc/impl/codegen/alloc.h>
+
+#include <functional>
+#include <vector>
+
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/security/context/security_context.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/transport/metadata_batch.h"
+
+/// An interface to define filters.
+///
+/// To define a filter, implement a subclass of each of \c CallData and
+/// \c ChannelData. Then register the filter using something like this:
+/// \code{.cpp}
+///   RegisterChannelFilter<MyChannelDataSubclass, MyCallDataSubclass>(
+///       "name-of-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr);
+/// \endcode
+
+namespace grpc {
+
+/// A C++ wrapper for the \c grpc_metadata_batch struct.
+class MetadataBatch {
+ public:
+  /// Borrows a pointer to \a batch, but does NOT take ownership.
+  /// The caller must ensure that \a batch continues to exist for as
+  /// long as the MetadataBatch object does.
+  explicit MetadataBatch(grpc_metadata_batch *batch) : batch_(batch) {}
+
+  grpc_metadata_batch *batch() const { return batch_; }
+
+  /// 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);
+
+  class const_iterator : public std::iterator<std::bidirectional_iterator_tag,
+                                              const grpc_mdelem> {
+   public:
+    const grpc_mdelem &operator*() const { return *elem_->md; }
+    const grpc_mdelem *operator->() const { return elem_->md; }
+
+    const_iterator &operator++() {
+      elem_ = elem_->next;
+      return *this;
+    }
+    const_iterator operator++(int) {
+      const_iterator tmp(*this);
+      operator++();
+      return tmp;
+    }
+    const_iterator &operator--() {
+      elem_ = elem_->prev;
+      return *this;
+    }
+    const_iterator operator--(int) {
+      const_iterator tmp(*this);
+      operator--();
+      return tmp;
+    }
+
+    bool operator==(const const_iterator &other) const {
+      return elem_ == other.elem_;
+    }
+    bool operator!=(const const_iterator &other) const {
+      return elem_ != other.elem_;
+    }
+
+   private:
+    friend class MetadataBatch;
+    explicit const_iterator(grpc_linked_mdelem *elem) : elem_(elem) {}
+
+    grpc_linked_mdelem *elem_;
+  };
+
+  const_iterator begin() const { return const_iterator(batch_->list.head); }
+  const_iterator end() const { return const_iterator(nullptr); }
+
+ private:
+  grpc_metadata_batch *batch_;  // Not owned.
+};
+
+/// A C++ wrapper for the \c grpc_transport_op struct.
+class TransportOp {
+ public:
+  /// Borrows a pointer to \a op, but does NOT take ownership.
+  /// The caller must ensure that \a op continues to exist for as
+  /// long as the TransportOp object does.
+  explicit TransportOp(grpc_transport_op *op) : op_(op) {}
+
+  grpc_transport_op *op() const { return op_; }
+
+  // TODO(roth): Add a C++ wrapper for grpc_error?
+  grpc_error *disconnect_with_error() const {
+    return op_->disconnect_with_error;
+  }
+  bool send_goaway() const { return op_->send_goaway; }
+
+  // TODO(roth): Add methods for additional fields as needed.
+
+ private:
+  grpc_transport_op *op_;  // Not owned.
+};
+
+/// A C++ wrapper for the \c grpc_transport_stream_op struct.
+class TransportStreamOp {
+ public:
+  /// Borrows a pointer to \a op, but does NOT take ownership.
+  /// The caller must ensure that \a op continues to exist for as
+  /// long as the TransportStreamOp object does.
+  explicit TransportStreamOp(grpc_transport_stream_op *op)
+      : op_(op),
+        send_initial_metadata_(op->send_initial_metadata),
+        send_trailing_metadata_(op->send_trailing_metadata),
+        recv_initial_metadata_(op->recv_initial_metadata),
+        recv_trailing_metadata_(op->recv_trailing_metadata) {}
+
+  grpc_transport_stream_op *op() const { return op_; }
+
+  grpc_closure *on_complete() const { return op_->on_complete; }
+  void set_on_complete(grpc_closure *closure) { op_->on_complete = closure; }
+
+  MetadataBatch *send_initial_metadata() {
+    return op_->send_initial_metadata == nullptr ? nullptr
+                                                 : &send_initial_metadata_;
+  }
+  MetadataBatch *send_trailing_metadata() {
+    return op_->send_trailing_metadata == nullptr ? nullptr
+                                                  : &send_trailing_metadata_;
+  }
+  MetadataBatch *recv_initial_metadata() {
+    return op_->recv_initial_metadata == nullptr ? nullptr
+                                                 : &recv_initial_metadata_;
+  }
+  MetadataBatch *recv_trailing_metadata() {
+    return op_->recv_trailing_metadata == nullptr ? nullptr
+                                                  : &recv_trailing_metadata_;
+  }
+
+  uint32_t *send_initial_metadata_flags() const {
+    return &op_->send_initial_metadata_flags;
+  }
+
+  grpc_closure *recv_initial_metadata_ready() const {
+    return op_->recv_initial_metadata_ready;
+  }
+  void set_recv_initial_metadata_ready(grpc_closure *closure) {
+    op_->recv_initial_metadata_ready = closure;
+  }
+
+  grpc_byte_stream *send_message() const { return op_->send_message; }
+  void set_send_message(grpc_byte_stream *send_message) {
+    op_->send_message = send_message;
+  }
+
+  /// To be called only on clients and servers, respectively.
+  grpc_client_security_context *client_security_context() const {
+    return (grpc_client_security_context *)op_->context[GRPC_CONTEXT_SECURITY]
+        .value;
+  }
+  grpc_server_security_context *server_security_context() const {
+    return (grpc_server_security_context *)op_->context[GRPC_CONTEXT_SECURITY]
+        .value;
+  }
+
+  census_context *get_census_context() const {
+    return (census_context *)op_->context[GRPC_CONTEXT_TRACING].value;
+  }
+
+ private:
+  grpc_transport_stream_op *op_;  // Not owned.
+  MetadataBatch send_initial_metadata_;
+  MetadataBatch send_trailing_metadata_;
+  MetadataBatch recv_initial_metadata_;
+  MetadataBatch recv_trailing_metadata_;
+};
+
+/// Represents channel data.
+class ChannelData {
+ public:
+  virtual ~ChannelData() {
+    if (peer_) gpr_free((void *)peer_);
+  }
+
+  /// Caller does NOT take ownership of result.
+  const char *peer() const { return peer_; }
+
+  // TODO(roth): Find a way to avoid passing elem into these methods.
+  virtual void StartTransportOp(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem, TransportOp *op);
+
+ protected:
+  /// Takes ownership of \a peer.
+  ChannelData(const grpc_channel_args &args, const char *peer) : peer_(peer) {}
+
+ private:
+  const char *peer_;
+};
+
+/// Represents call data.
+class CallData {
+ public:
+  virtual ~CallData() {}
+
+  /// Initializes the call data.
+  virtual grpc_error *Init() { return GRPC_ERROR_NONE; }
+
+  // TODO(roth): Find a way to avoid passing elem into these methods.
+
+  /// Starts a new stream operation.
+  virtual void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
+                                      grpc_call_element *elem,
+                                      TransportStreamOp *op);
+
+  /// Sets a pollset or pollset set.
+  virtual void SetPollsetOrPollsetSet(grpc_exec_ctx *exec_ctx,
+                                      grpc_call_element *elem,
+                                      grpc_polling_entity *pollent);
+
+  /// Gets the peer name.
+  virtual char *GetPeer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+
+ protected:
+  explicit CallData(const ChannelData &) {}
+};
+
+namespace internal {
+
+// Defines static members for passing to C core.
+// Members of this class correspond to the members of the C
+// grpc_channel_filter struct.
+template <typename ChannelDataType, typename CallDataType>
+class ChannelFilter GRPC_FINAL {
+ 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 void DestroyChannelElement(grpc_exec_ctx *exec_ctx,
+                                    grpc_channel_element *elem) {
+    reinterpret_cast<ChannelDataType *>(elem->channel_data)->~ChannelDataType();
+  }
+
+  static void StartTransportOp(grpc_exec_ctx *exec_ctx,
+                               grpc_channel_element *elem,
+                               grpc_transport_op *op) {
+    ChannelDataType *channel_data = (ChannelDataType *)elem->channel_data;
+    TransportOp op_wrapper(op);
+    channel_data->StartTransportOp(exec_ctx, elem, &op_wrapper);
+  }
+
+  static const size_t call_data_size = sizeof(CallDataType);
+
+  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;
+    // Construct the object in the already-allocated memory.
+    CallDataType *call_data = new (elem->call_data) CallDataType(channel_data);
+    return call_data->Init();
+  }
+
+  static void DestroyCallElement(grpc_exec_ctx *exec_ctx,
+                                 grpc_call_element *elem,
+                                 const grpc_call_final_info *final_info,
+                                 void *and_free_memory) {
+    reinterpret_cast<CallDataType *>(elem->call_data)->~CallDataType();
+  }
+
+  static void StartTransportStreamOp(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_element *elem,
+                                     grpc_transport_stream_op *op) {
+    CallDataType *call_data = (CallDataType *)elem->call_data;
+    TransportStreamOp op_wrapper(op);
+    call_data->StartTransportStreamOp(exec_ctx, elem, &op_wrapper);
+  }
+
+  static void SetPollsetOrPollsetSet(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_element *elem,
+                                     grpc_polling_entity *pollent) {
+    CallDataType *call_data = (CallDataType *)elem->call_data;
+    call_data->SetPollsetOrPollsetSet(exec_ctx, elem, pollent);
+  }
+
+  static char *GetPeer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+    CallDataType *call_data = (CallDataType *)elem->call_data;
+    return call_data->GetPeer(exec_ctx, elem);
+  }
+};
+
+struct FilterRecord {
+  grpc_channel_stack_type stack_type;
+  int priority;
+  std::function<bool(const grpc_channel_args &)> include_filter;
+  grpc_channel_filter filter;
+};
+extern std::vector<FilterRecord> *channel_filters;
+
+void ChannelFilterPluginInit();
+void ChannelFilterPluginShutdown();
+
+}  // namespace internal
+
+/// Registers a new filter.
+/// Must be called by only one thread at a time.
+/// The \a include_filter argument specifies a function that will be called
+/// to determine at run-time whether or not to add the filter. If the
+/// value is nullptr, the filter will be added unconditionally.
+template <typename ChannelDataType, typename CallDataType>
+void RegisterChannelFilter(
+    const char *name, grpc_channel_stack_type stack_type, int priority,
+    std::function<bool(const grpc_channel_args &)> include_filter) {
+  // If we haven't been called before, initialize channel_filters and
+  // call grpc_register_plugin().
+  if (internal::channel_filters == nullptr) {
+    grpc_register_plugin(internal::ChannelFilterPluginInit,
+                         internal::ChannelFilterPluginShutdown);
+    internal::channel_filters = new std::vector<internal::FilterRecord>();
+  }
+  // Add an entry to channel_filters. The filter will be added when the
+  // C-core initialization code calls ChannelFilterPluginInit().
+  typedef internal::ChannelFilter<ChannelDataType, CallDataType> FilterType;
+  internal::FilterRecord filter_record = {
+      stack_type,
+      priority,
+      include_filter,
+      {FilterType::StartTransportStreamOp, FilterType::StartTransportOp,
+       FilterType::call_data_size, FilterType::InitCallElement,
+       FilterType::SetPollsetOrPollsetSet, FilterType::DestroyCallElement,
+       FilterType::channel_data_size, FilterType::InitChannelElement,
+       FilterType::DestroyChannelElement, FilterType::GetPeer, name}};
+  internal::channel_filters->push_back(filter_record);
+}
+
+}  // namespace grpc
+
+#endif  // GRPCXX_CHANNEL_FILTER_H
diff --git a/src/cpp/ext/proto_server_reflection.h b/src/cpp/ext/proto_server_reflection.h
index 23c1305..f66f3c2 100644
--- a/src/cpp/ext/proto_server_reflection.h
+++ b/src/cpp/ext/proto_server_reflection.h
@@ -30,13 +30,31 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+
+/*
+  - If the generated header `grpc++/ext/reflection.grpc.pb.h` needs to be
+    installed, target `grpc++_reflection` in `build.yaml` should use the
+    filegroup `grpc++_reflection_proto`, and GRPC_NO_GENERATED_CODE should not
+    be defined.
+  - If the server reflection library needs to generate `reflection.grpc.pb.h`
+    from `reflection.proto` at compile time, the generated header
+    `grpc++/ext/reflection.grpc.pb.h` should not be installed. In this case,
+    target `grpc++_reflection` should depend on `grpc++_reflection_codegen`, and
+    GRPC_NO_GENERATED_CODE should be defined.
+*/
+
 #ifndef GRPC_INTERNAL_CPP_EXT_PROTO_SERVER_REFLECTION_H
 #define GRPC_INTERNAL_CPP_EXT_PROTO_SERVER_REFLECTION_H
 
 #include <unordered_set>
 #include <vector>
 
+// GRPC_NO_GENERATED_CODE indicates generated pb files should not be used
+#ifdef GRPC_NO_GENERATED_CODE
+#include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h"
+#else
 #include <grpc++/ext/reflection.grpc.pb.h>
+#endif  // GRPC_NO_GENERATED_CODE
 #include <grpc++/grpc++.h>
 
 namespace grpc {
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index c2cd20e..4c4772a 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -37,12 +37,19 @@
 namespace grpc {
 
 ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) {
-  // TODO(yangg) maybe expose some core API to simplify this
-  std::vector<gpr_slice> c_slices(nslices);
-  for (size_t i = 0; i < nslices; i++) {
-    c_slices[i] = slices[i].slice_;
-  }
-  buffer_ = grpc_raw_byte_buffer_create(c_slices.data(), nslices);
+  // The following assertions check that the representation of a grpc::Slice is
+  // identical to that of a gpr_slice:  it has a gpr_slice field, and nothing
+  // else.
+  static_assert(std::is_same<decltype(slices[0].slice_), gpr_slice>::value,
+                "Slice must have same representation as gpr_slice");
+  static_assert(sizeof(Slice) == sizeof(gpr_slice),
+                "Slice must have same representation as gpr_slice");
+  // The const_cast is legal if grpc_raw_byte_buffer_create() does no more
+  // than its advertised side effect of increasing the reference count of the
+  // slices it processes, and such an increase does not affect the semantics
+  // seen by the caller of this constructor.
+  buffer_ = grpc_raw_byte_buffer_create(
+      reinterpret_cast<gpr_slice*>(const_cast<Slice*>(slices)), nslices);
 }
 
 ByteBuffer::~ByteBuffer() {
@@ -95,4 +102,10 @@
   return *this;
 }
 
+void ByteBuffer::Swap(ByteBuffer* other) {
+  grpc_byte_buffer* tmp = other->buffer_;
+  other->buffer_ = this->buffer_;
+  this->buffer_ = tmp;
+}
+
 }  // namespace grpc
diff --git a/src/csharp/Grpc.Auth/project.json b/src/csharp/Grpc.Auth/project.json
index fce8b59..30f0944 100644
--- a/src/csharp/Grpc.Auth/project.json
+++ b/src/csharp/Grpc.Auth/project.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.0.1-pre1",
+  "version": "1.1.0-dev",
   "title": "gRPC C# Auth",
   "authors": [ "Google Inc." ],
   "copyright": "Copyright 2015, Google Inc.",
@@ -22,7 +22,7 @@
     }
   },
   "dependencies": {
-    "Grpc.Core": "1.0.1-pre1",
+    "Grpc.Core": "1.1.0-dev",
     "Google.Apis.Auth": "1.15.0"
   },
   "frameworks": {
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index eeed699..574e900 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -47,7 +47,6 @@
     /// </summary>
     public class GrpcEnvironment
     {
-        const LogLevel DefaultLogLevel = LogLevel.Info;
         const int MinDefaultThreadPoolSize = 4;
 
         static object staticLock = new object();
@@ -58,7 +57,7 @@
         static readonly HashSet<Channel> registeredChannels = new HashSet<Channel>();
         static readonly HashSet<Server> registeredServers = new HashSet<Server>();
 
-        static ILogger logger = new LogLevelFilterLogger(new ConsoleLogger(), DefaultLogLevel);
+        static ILogger logger = new NullLogger();
 
         readonly object myLock = new object();
         readonly GrpcThreadPool threadPool;
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index febd7a2..553aeec 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -48,11 +48,11 @@
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "1.0.1.0";
+        public const string CurrentAssemblyFileVersion = "1.1.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.0.1-pre1";
+        public const string CurrentVersion = "1.1.0-dev";
     }
 }
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
index 4e99656..f7e21a2 100644
--- a/src/csharp/Grpc.Core/project.json
+++ b/src/csharp/Grpc.Core/project.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.0.1-pre1",
+  "version": "1.1.0-dev",
   "title": "gRPC C# Core",
   "authors": [ "Google Inc." ],
   "copyright": "Copyright 2015, Google Inc.",
diff --git a/src/csharp/Grpc.HealthCheck/project.json b/src/csharp/Grpc.HealthCheck/project.json
index af0b92b..7c062a7 100644
--- a/src/csharp/Grpc.HealthCheck/project.json
+++ b/src/csharp/Grpc.HealthCheck/project.json
@@ -1,5 +1,5 @@
 {
-  "version": "1.0.1-pre1",
+  "version": "1.1.0-dev",
   "title": "gRPC C# Healthchecking",
   "authors": [ "Google Inc." ],
   "copyright": "Copyright 2015, Google Inc.",
@@ -22,7 +22,7 @@
     }
   },
   "dependencies": {
-    "Grpc.Core": "1.0.1-pre1",
+    "Grpc.Core": "1.1.0-dev",
     "Google.Protobuf": "3.0.0-beta3"
   },
   "frameworks": {
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index b1ca9cd..b92189c 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -30,7 +30,7 @@
 @rem Builds gRPC NuGet packages
 
 @rem Current package versions
-set VERSION=1.0.1-pre1
+set VERSION=1.1.0-dev
 set PROTOBUF_VERSION=3.0.0
 
 @rem Adjust the location of nuget.exe
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
index 7e5dbb5..e673359 100644
--- a/src/node/health_check/package.json
+++ b/src/node/health_check/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc-health-check",
-  "version": "1.0.1-pre1",
+  "version": "1.1.0-dev",
   "author": "Google Inc.",
   "description": "Health check service for use with gRPC",
   "repository": {
@@ -15,7 +15,7 @@
     }
   ],
   "dependencies": {
-    "grpc": "^1.0.1-pre1",
+    "grpc": "^1.1.0-dev",
     "lodash": "^3.9.3",
     "google-protobuf": "^3.0.0"
   },
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index fd22e75..e5513d7 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc-tools",
-  "version": "1.0.1-pre1",
+  "version": "1.1.0-dev",
   "author": "Google Inc.",
   "description": "Tools for developing with gRPC on Node.js",
   "homepage": "http://www.grpc.io/",
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index da9473f..05a1d10 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -208,13 +208,9 @@
         // don't want to throw, because the app shouldn't crash for a behavior
         // that's on the hands of any server to have. Instead we finish and ask
         // the server to cancel.
-        //
-        // TODO(jcanizales): No canonical code is appropriate for this situation
-        // (because it's just a client problem). Use another domain and an
-        // appropriately-documented code.
         [weakSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
-                                                      code:GRPCErrorCodeInternal
-                                                  userInfo:nil]];
+                                                      code:GRPCErrorCodeResourceExhausted
+                                                  userInfo:@{NSLocalizedDescriptionKey: @"Client does not have enough memory to hold the server response."}]];
         [weakSelf cancelCall];
         return;
       }
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 40e78a9..5bada2d 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -59,8 +59,8 @@
  * Creates a secure channel to the specified @c host using Cronet as a transport mechanism.
  */
 #ifdef GRPC_COMPILE_WITH_CRONET
-+ (nullable GRPCChannel *)secureCronetChannelWithHost:(NSString *)host
-                                          channelArgs:(NSDictionary *)channelArgs;
++ (nullable GRPCChannel *)secureCronetChannelWithHost:(nonnull NSString *)host
+                                          channelArgs:(nonnull NSDictionary *)channelArgs;
 #endif
 /**
  * Creates a secure channel to the specified @c host using the specified @c credentials and
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist b/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
new file mode 100644
index 0000000..fbeeb96
--- /dev/null
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
diff --git a/src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist b/src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist
new file mode 100644
index 0000000..ba72822
--- /dev/null
+++ b/src/objective-c/tests/InteropTestsRemoteWithCronet/Info.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>BNDL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+</dict>
+</plist>
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
similarity index 71%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
index df2324c..fab8ad8 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/src/objective-c/tests/InteropTestsRemoteWithCronet/InteropTestsRemoteWithCronet.m
@@ -31,17 +31,20 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#import <GRPCClient/GRPCCall+Tests.h>
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#import "InteropTests.h"
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+static NSString * const kRemoteSSLHost = @"grpc-test.sandbox.googleapis.com";
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+/** Tests in InteropTests.m, sending the RPCs to a remote SSL server. */
+@interface InteropTestsRemoteWithCronet : InteropTests
+@end
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+@implementation InteropTestsRemoteWithCronet
+
++ (NSString *)host {
+  return kRemoteSSLHost;
+}
+
+@end
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 17b9740..17478fa 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -14,6 +14,7 @@
   InteropTestsRemote
   InteropTestsLocalSSL
   InteropTestsLocalCleartext
+  InteropTestsRemoteWithCronet
 ).each do |target_name|
   target target_name do
     pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
@@ -22,17 +23,29 @@
     pod '!ProtoCompiler-gRPCPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
 
     pod 'BoringSSL',       :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
-    pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
 
     pod 'gRPC',           :path => GRPC_LOCAL_SRC
     pod 'gRPC-Core',      :path => GRPC_LOCAL_SRC
     pod 'gRPC-RxLibrary', :path => GRPC_LOCAL_SRC
     pod 'gRPC-ProtoRPC',  :path => GRPC_LOCAL_SRC
-
     pod 'RemoteTest', :path => "RemoteTestClient"
+
+    if target_name == 'InteropTestsRemoteWithCronet'
+      pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
+      pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
+    end
   end
 end
 
+target 'CoreCronetEnd2EndTests' do
+  pod 'BoringSSL', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
+  pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
+  pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-Core/Cronet-Interface', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
+  pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC
+end
+
 # gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's
 # pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded
 # and before they are installed in the user project.
@@ -69,7 +82,11 @@
     target.build_configurations.each do |config|
       config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES'
     end
-    if target.name == 'gRPC-Core'
+
+    # CocoaPods creates duplicated library targets of gRPC-Core when the test targets include
+    # non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core.'
+    # and require the same error suppresion.
+    if target.name == 'gRPC-Core' or target.name.start_with?('gRPC-Core.') 
       target.build_configurations.each do |config|
         # TODO(zyc): Remove this setting after the issue is resolved
         # GPR_UNREACHABLE_CODE causes "Control may reach end of non-void
@@ -77,5 +94,15 @@
         config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'NO'
       end
     end
+
+    # Activate Cronet for the dedicated build configuration 'Cronet', which will be used solely by
+    # the test target 'InteropTestsRemoteWithCronet'
+    if target.name == 'gRPC'
+      target.build_configurations.each do |config|
+        if config.name == 'Cronet'
+          config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_COMPILE_WITH_CRONET=1'
+        end
+      end
+    end
   end
 end
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index f9389a4..c4a6567 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -7,11 +7,18 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		09B76D9585ACE7403804D9DC /* libPods-InteropTestsRemoteWithCronet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */; };
 		0F9232F984C08643FD40C34F /* libPods-InteropTestsRemote.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */; };
 		16A9E77B6E336B3C0B9BA6E0 /* libPods-InteropTestsLocalSSL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DBEDE45BDA60DF1E1C8950C0 /* libPods-InteropTestsLocalSSL.a */; };
 		20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; };
 		333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; };
 		3D7C85F6AA68C4A205E3BA16 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */; };
+		5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */; };
+		5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
+		5EE84BF41D4717E40050C6CC /* InteropTestsRemoteWithCronet.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */; };
+		5EE84BF61D4717E40050C6CC /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
+		5EE84BFE1D471D400050C6CC /* InteropTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635ED2EB1B1A3BC400FDE5C3 /* InteropTests.m */; };
+		60D2A57ED559F34428C2EEC5 /* libPods-CoreCronetEnd2EndTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */; };
 		6312AE4E1B1BF49B00341DEE /* GRPCClientTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */; };
 		63423F4A1B150A5F006CF63C /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
 		635697CD1B14FC11007A7283 /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 635697CC1B14FC11007A7283 /* Tests.m */; };
@@ -38,6 +45,20 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
+		5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 635697C61B14FC11007A7283;
+			remoteInfo = Tests;
+		};
+		5EE84BF71D4717E40050C6CC /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 635697C61B14FC11007A7283;
+			remoteInfo = Tests;
+		};
 		63423F4B1B150A5F006CF63C /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 635697BF1B14FC11007A7283 /* Project object */;
@@ -91,12 +112,24 @@
 		060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = "<group>"; };
 		07D10A965323BEA7FE59A74B /* Pods-RxLibraryUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.debug.xcconfig"; sourceTree = "<group>"; };
 		0A4F89D9C90E9C30990218F0 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
+		0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.debug.xcconfig"; sourceTree = "<group>"; };
+		14B09A58FEE53A7A6B838920 /* Pods-InteropTestsLocalSSL.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.cronet.xcconfig"; sourceTree = "<group>"; };
+		17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.debug.xcconfig"; sourceTree = "<group>"; };
 		20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Tests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		35F2B6BF3BAE8F0DC4AFD76E /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.release.xcconfig"; sourceTree = "<group>"; };
+		3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.cronet.xcconfig"; sourceTree = "<group>"; };
+		4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.release.xcconfig"; sourceTree = "<group>"; };
+		4ADEA1C8BBE10D90940AC68E /* Pods-InteropTestsRemote.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.cronet.xcconfig"; sourceTree = "<group>"; };
 		51A275E86C141416ED63FF76 /* Pods-InteropTestsLocalCleartext.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.release.xcconfig"; sourceTree = "<group>"; };
 		553BBBED24E4162D1F769D65 /* Pods-InteropTestsLocalSSL.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.debug.xcconfig"; sourceTree = "<group>"; };
+		573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; sourceTree = "<group>"; };
 		5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
+		5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CoreCronetEnd2EndTests.m; sourceTree = "<group>"; };
+		5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InteropTestsRemoteWithCronet.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = InteropTestsRemoteWithCronet.m; sourceTree = "<group>"; };
+		5EE84BF51D4717E40050C6CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		6312AE4D1B1BF49B00341DEE /* GRPCClientTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GRPCClientTests.m; sourceTree = "<group>"; };
 		63423F441B150A5F006CF63C /* AllTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AllTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		63423F501B151B77006CF63C /* RxLibraryUnitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RxLibraryUnitTests.m; sourceTree = "<group>"; };
@@ -113,8 +146,12 @@
 		63E240CC1B6C4D3A005F3B0E /* InteropTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InteropTests.h; sourceTree = "<group>"; };
 		63E240CD1B6C4E2B005F3B0E /* InteropTestsLocalSSL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InteropTestsLocalSSL.m; sourceTree = "<group>"; };
 		63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TestCertificates.bundle; sourceTree = "<group>"; };
+		79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RxLibraryUnitTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests.cronet.xcconfig"; sourceTree = "<group>"; };
 		7A2E97E3F469CC2A758D77DE /* Pods-InteropTestsLocalSSL.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalSSL.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL.release.xcconfig"; sourceTree = "<group>"; };
+		9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemoteWithCronet.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RxLibraryUnitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+		AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.cronet.xcconfig"; sourceTree = "<group>"; };
+		AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemoteWithCronet.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet.release.xcconfig"; sourceTree = "<group>"; };
 		B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.debug.xcconfig"; sourceTree = "<group>"; };
 		CAE086D5B470DA367D415AB0 /* libPods-AllTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AllTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsRemote.a"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -123,11 +160,32 @@
 		E1486220285AF123EB124008 /* Pods-InteropTestsLocalCleartext.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsLocalCleartext.debug.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsLocalCleartext/Pods-InteropTestsLocalCleartext.debug.xcconfig"; sourceTree = "<group>"; };
 		E4275A759BDBDF143B9B438F /* Pods-InteropTestsRemote.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InteropTestsRemote.release.xcconfig"; path = "Pods/Target Support Files/Pods-InteropTestsRemote/Pods-InteropTestsRemote.release.xcconfig"; sourceTree = "<group>"; };
 		E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = "<group>"; };
+		E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.cronet.xcconfig"; sourceTree = "<group>"; };
+		F671D4CAD2864FB203B920B4 /* Pods-Tests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.cronet.xcconfig"; sourceTree = "<group>"; };
+		FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CoreCronetEnd2EndTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InteropTestsLocalCleartext.a"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FF7B5489BCFE40111D768DD0 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
+		5E8A5DA11D3840B4000F8BC4 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */,
+				60D2A57ED559F34428C2EEC5 /* libPods-CoreCronetEnd2EndTests.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		5EE84BEE1D4717E40050C6CC /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5EE84BF61D4717E40050C6CC /* libTests.a in Frameworks */,
+				09B76D9585ACE7403804D9DC /* libPods-InteropTestsRemoteWithCronet.a in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		63423F411B150A5F006CF63C /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -194,6 +252,8 @@
 				DBE059B4AC7A51919467EEC0 /* libPods-InteropTestsRemote.a */,
 				A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */,
 				20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */,
+				FBD98AC417B9882D32B19F28 /* libPods-CoreCronetEnd2EndTests.a */,
+				9E9444C764F0FFF64A7EB58E /* libPods-InteropTestsRemoteWithCronet.a */,
 			);
 			name = Frameworks;
 			sourceTree = "<group>";
@@ -215,15 +275,46 @@
 				3B0861FC805389C52DB260D4 /* Pods-RxLibraryUnitTests.release.xcconfig */,
 				060EF32D7EC0DF67ED617507 /* Pods-Tests.debug.xcconfig */,
 				E6733B838B28453434B556E2 /* Pods-Tests.release.xcconfig */,
+				0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */,
+				4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */,
+				17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */,
+				AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */,
+				E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */,
+				573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */,
+				AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */,
+				14B09A58FEE53A7A6B838920 /* Pods-InteropTestsLocalSSL.cronet.xcconfig */,
+				4ADEA1C8BBE10D90940AC68E /* Pods-InteropTestsRemote.cronet.xcconfig */,
+				3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */,
+				79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */,
+				F671D4CAD2864FB203B920B4 /* Pods-Tests.cronet.xcconfig */,
 			);
 			name = Pods;
 			sourceTree = "<group>";
 		};
+		5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
+			isa = PBXGroup;
+			children = (
+				5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */,
+			);
+			path = CoreCronetEnd2EndTests;
+			sourceTree = "<group>";
+		};
+		5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = {
+			isa = PBXGroup;
+			children = (
+				5EE84BF31D4717E40050C6CC /* InteropTestsRemoteWithCronet.m */,
+				5EE84BF51D4717E40050C6CC /* Info.plist */,
+			);
+			path = InteropTestsRemoteWithCronet;
+			sourceTree = "<group>";
+		};
 		635697BE1B14FC11007A7283 = {
 			isa = PBXGroup;
 			children = (
 				635697C91B14FC11007A7283 /* Tests */,
 				63E240CF1B6C63DC005F3B0E /* TestCertificates.bundle */,
+				5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
+				5EE84BF21D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
 				635697C81B14FC11007A7283 /* Products */,
 				51E4650F34F854F41FF053B3 /* Pods */,
 				136D535E19727099B941D7B1 /* Frameworks */,
@@ -239,6 +330,8 @@
 				63DC84231BE15267000708E8 /* InteropTestsRemote.xctest */,
 				63DC84341BE15294000708E8 /* InteropTestsLocalSSL.xctest */,
 				63DC84431BE152B5000708E8 /* InteropTestsLocalCleartext.xctest */,
+				5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */,
+				5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -270,6 +363,48 @@
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
+		5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */;
+			buildPhases = (
+				F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */,
+				5E8A5DA01D3840B4000F8BC4 /* Sources */,
+				5E8A5DA11D3840B4000F8BC4 /* Frameworks */,
+				5E8A5DA21D3840B4000F8BC4 /* Resources */,
+				E63468C760D0724F18861822 /* [CP] Embed Pods Frameworks */,
+				6DFE9E77CAB5760196D79E0F /* [CP] Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */,
+			);
+			name = CoreCronetEnd2EndTests;
+			productName = CoreCronetEnd2EndTests;
+			productReference = 5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		5EE84BF01D4717E40050C6CC /* InteropTestsRemoteWithCronet */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 5EE84BFB1D4717E40050C6CC /* Build configuration list for PBXNativeTarget "InteropTestsRemoteWithCronet" */;
+			buildPhases = (
+				C0F7B1FF6F88CC5FBF362F4C /* [CP] Check Pods Manifest.lock */,
+				5EE84BED1D4717E40050C6CC /* Sources */,
+				5EE84BEE1D4717E40050C6CC /* Frameworks */,
+				5EE84BEF1D4717E40050C6CC /* Resources */,
+				31F8D1C407195CBF0C02929B /* [CP] Embed Pods Frameworks */,
+				DB4D0E73C229F2FF3B364AB3 /* [CP] Copy Pods Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				5EE84BF81D4717E40050C6CC /* PBXTargetDependency */,
+			);
+			name = InteropTestsRemoteWithCronet;
+			productName = InteropTestsRemoteWithCronet;
+			productReference = 5EE84BF11D4717E40050C6CC /* InteropTestsRemoteWithCronet.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
 		63423F431B150A5F006CF63C /* AllTests */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */;
@@ -403,6 +538,12 @@
 				LastUpgradeCheck = 0630;
 				ORGANIZATIONNAME = gRPC;
 				TargetAttributes = {
+					5E8A5DA31D3840B4000F8BC4 = {
+						CreatedOnToolsVersion = 7.3.1;
+					};
+					5EE84BF01D4717E40050C6CC = {
+						CreatedOnToolsVersion = 7.3.1;
+					};
 					63423F431B150A5F006CF63C = {
 						CreatedOnToolsVersion = 6.3.1;
 					};
@@ -441,11 +582,27 @@
 				63DC84221BE15267000708E8 /* InteropTestsRemote */,
 				63DC84331BE15294000708E8 /* InteropTestsLocalSSL */,
 				63DC84421BE152B5000708E8 /* InteropTestsLocalCleartext */,
+				5E8A5DA31D3840B4000F8BC4 /* CoreCronetEnd2EndTests */,
+				5EE84BF01D4717E40050C6CC /* InteropTestsRemoteWithCronet */,
 			);
 		};
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
+		5E8A5DA21D3840B4000F8BC4 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		5EE84BEF1D4717E40050C6CC /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		63423F421B150A5F006CF63C /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -486,6 +643,21 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
+		31F8D1C407195CBF0C02929B /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
 		4C406327D3907A5E5FBA8AC9 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -561,6 +733,21 @@
 			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsLocalSSL/Pods-InteropTestsLocalSSL-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
+		6DFE9E77CAB5760196D79E0F /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
 		7418AC7B3844B29E48D24FC7 /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -696,6 +883,21 @@
 			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
 			showEnvVarsInLog = 0;
 		};
+		C0F7B1FF6F88CC5FBF362F4C /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
+			showEnvVarsInLog = 0;
+		};
 		C2E09DC4BD239F71160F0CC1 /* [CP] Copy Pods Resources */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
@@ -741,9 +943,71 @@
 			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RxLibraryUnitTests/Pods-RxLibraryUnitTests-resources.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
+		DB4D0E73C229F2FF3B364AB3 /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Copy Pods Resources";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-InteropTestsRemoteWithCronet/Pods-InteropTestsRemoteWithCronet-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		E63468C760D0724F18861822 /* [CP] Embed Pods Frameworks */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Embed Pods Frameworks";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests-frameworks.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
+		F58F17E425446B15028B9F74 /* [CP] Check Pods Manifest.lock */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "[CP] Check Pods Manifest.lock";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n    cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n    exit 1\nfi\n";
+			showEnvVarsInLog = 0;
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
+		5E8A5DA01D3840B4000F8BC4 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		5EE84BED1D4717E40050C6CC /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				5EE84BFE1D471D400050C6CC /* InteropTests.m in Sources */,
+				5EE84BF41D4717E40050C6CC /* InteropTestsRemoteWithCronet.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		63423F401B150A5F006CF63C /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -804,6 +1068,16 @@
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+		5E8A5DAB1D3840B4000F8BC4 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 635697C61B14FC11007A7283 /* Tests */;
+			targetProxy = 5E8A5DAA1D3840B4000F8BC4 /* PBXContainerItemProxy */;
+		};
+		5EE84BF81D4717E40050C6CC /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 635697C61B14FC11007A7283 /* Tests */;
+			targetProxy = 5EE84BF71D4717E40050C6CC /* PBXContainerItemProxy */;
+		};
 		63423F4C1B150A5F006CF63C /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 635697C61B14FC11007A7283 /* Tests */;
@@ -832,6 +1106,248 @@
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
+		5E8A5DAC1D3840B4000F8BC4 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 0D2284C3DF7E57F0ED504E39 /* Pods-CoreCronetEnd2EndTests.debug.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
+			};
+			name = Debug;
+		};
+		5E8A5DAD1D3840B4000F8BC4 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 4AD97096D13D7416DC91A72A /* Pods-CoreCronetEnd2EndTests.release.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
+			};
+			name = Release;
+		};
+		5EC3C7A01D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+			};
+			name = Cronet;
+		};
+		5EC3C7A11D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = F671D4CAD2864FB203B920B4 /* Pods-Tests.cronet.xcconfig */;
+			buildSettings = {
+				GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SKIP_INSTALL = YES;
+			};
+			name = Cronet;
+		};
+		5EC3C7A21D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = E7E4D3FD76E3B745D992AF5F /* Pods-AllTests.cronet.xcconfig */;
+			buildSettings = {
+				FRAMEWORK_SEARCH_PATHS = (
+					"$(SDKROOT)/Developer/Library/Frameworks",
+					"$(inherited)",
+				);
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				INFOPLIST_FILE = Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Cronet;
+		};
+		5EC3C7A31D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 79C68EFFCB5533475D810B79 /* Pods-RxLibraryUnitTests.cronet.xcconfig */;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.RxLibraryUnitTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Cronet;
+		};
+		5EC3C7A41D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 4ADEA1C8BBE10D90940AC68E /* Pods-InteropTestsRemote.cronet.xcconfig */;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Cronet;
+		};
+		5EC3C7A51D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 14B09A58FEE53A7A6B838920 /* Pods-InteropTestsLocalSSL.cronet.xcconfig */;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalSSL;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Cronet;
+		};
+		5EC3C7A61D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = AA7CB64B4DD9915AE7C03163 /* Pods-InteropTestsLocalCleartext.cronet.xcconfig */;
+			buildSettings = {
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsLocalCleartext;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Cronet;
+		};
+		5EC3C7A71D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				INFOPLIST_FILE = CoreCronetEnd2EndTests/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CoreCronetEnd2EndTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				USER_HEADER_SEARCH_PATHS = "$(inherited) \"${PODS_ROOT}/../../../..\"";
+			};
+			name = Cronet;
+		};
+		5EC3C7A81D4FC18C000330E2 /* Cronet */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 3F27B2E744482771EB93C394 /* Pods-InteropTestsRemoteWithCronet.cronet.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"$(inherited)",
+					"COCOAPODS=1",
+					"$(inherited)",
+					"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
+					"GRPC_COMPILE_WITH_CRONET=1",
+				);
+				INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Cronet;
+		};
+		5EE84BF91D4717E40050C6CC /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 17F60BF2871F6AF85FB3FA12 /* Pods-InteropTestsRemoteWithCronet.debug.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_TESTABILITY = YES;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"$(inherited)",
+					"COCOAPODS=1",
+					"$(inherited)",
+					"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
+				);
+				INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		5EE84BFA1D4717E40050C6CC /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = AC414EF7A6BF76ED02B6E480 /* Pods-InteropTestsRemoteWithCronet.release.xcconfig */;
+			buildSettings = {
+				CLANG_ANALYZER_NONNULL = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"$(inherited)",
+					"COCOAPODS=1",
+					"$(inherited)",
+					"GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1",
+					"GRPC_COMPILE_WITH_CRONET=1",
+				);
+				INFOPLIST_FILE = InteropTestsRemoteWithCronet/Info.plist;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
+				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+				PRODUCT_BUNDLE_IDENTIFIER = io.grpc.InteropTestsRemoteWithCronet;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
 		63423F4E1B150A5F006CF63C /* Debug */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = B94C27C06733CF98CE1B2757 /* Pods-AllTests.debug.xcconfig */;
@@ -1071,10 +1587,31 @@
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
+		5E8A5DAE1D3840B4000F8BC4 /* Build configuration list for PBXNativeTarget "CoreCronetEnd2EndTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				5E8A5DAC1D3840B4000F8BC4 /* Debug */,
+				5EC3C7A71D4FC18C000330E2 /* Cronet */,
+				5E8A5DAD1D3840B4000F8BC4 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		5EE84BFB1D4717E40050C6CC /* Build configuration list for PBXNativeTarget "InteropTestsRemoteWithCronet" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				5EE84BF91D4717E40050C6CC /* Debug */,
+				5EC3C7A81D4FC18C000330E2 /* Cronet */,
+				5EE84BFA1D4717E40050C6CC /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		63423F4D1B150A5F006CF63C /* Build configuration list for PBXNativeTarget "AllTests" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				63423F4E1B150A5F006CF63C /* Debug */,
+				5EC3C7A21D4FC18C000330E2 /* Cronet */,
 				63423F4F1B150A5F006CF63C /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
@@ -1084,6 +1621,7 @@
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				635697D91B14FC11007A7283 /* Debug */,
+				5EC3C7A01D4FC18C000330E2 /* Cronet */,
 				635697DA1B14FC11007A7283 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
@@ -1093,6 +1631,7 @@
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				635697DC1B14FC11007A7283 /* Debug */,
+				5EC3C7A11D4FC18C000330E2 /* Cronet */,
 				635697DD1B14FC11007A7283 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
@@ -1102,6 +1641,7 @@
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				63DC841C1BE15179000708E8 /* Debug */,
+				5EC3C7A31D4FC18C000330E2 /* Cronet */,
 				63DC841D1BE15179000708E8 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
@@ -1111,6 +1651,7 @@
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				63DC842C1BE15267000708E8 /* Debug */,
+				5EC3C7A41D4FC18C000330E2 /* Cronet */,
 				63DC842D1BE15267000708E8 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
@@ -1120,6 +1661,7 @@
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				63DC843D1BE15294000708E8 /* Debug */,
+				5EC3C7A51D4FC18C000330E2 /* Cronet */,
 				63DC843E1BE15294000708E8 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
@@ -1129,6 +1671,7 @@
 			isa = XCConfigurationList;
 			buildConfigurations = (
 				63DC844C1BE152B5000708E8 /* Debug */,
+				5EC3C7A61D4FC18C000330E2 /* Cronet */,
 				63DC844D1BE152B5000708E8 /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
new file mode 100644
index 0000000..a1da2e0
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/CoreCronetEnd2EndTests.xcscheme
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0730"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+               BuildableName = "CoreCronetEnd2EndTests.xctest"
+               BlueprintName = "CoreCronetEnd2EndTests"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+               BuildableName = "CoreCronetEnd2EndTests.xctest"
+               BlueprintName = "CoreCronetEnd2EndTests"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+            BuildableName = "CoreCronetEnd2EndTests.xctest"
+            BlueprintName = "CoreCronetEnd2EndTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+            BuildableName = "CoreCronetEnd2EndTests.xctest"
+            BlueprintName = "CoreCronetEnd2EndTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5E8A5DA31D3840B4000F8BC4"
+            BuildableName = "CoreCronetEnd2EndTests.xctest"
+            BlueprintName = "CoreCronetEnd2EndTests"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme
new file mode 100644
index 0000000..1d21111
--- /dev/null
+++ b/src/objective-c/tests/Tests.xcodeproj/xcshareddata/xcschemes/InteropTestsRemoteWithCronet.xcscheme
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "0730"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
+               BuildableName = "InteropTestsRemoteWithCronet.xctest"
+               BlueprintName = "InteropTestsRemoteWithCronet"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Cronet"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
+               BuildableName = "InteropTestsRemoteWithCronet.xctest"
+               BlueprintName = "InteropTestsRemoteWithCronet"
+               ReferencedContainer = "container:Tests.xcodeproj">
+            </BuildableReference>
+            <SkippedTests>
+               <Test
+                  Identifier = "InteropTests">
+               </Test>
+            </SkippedTests>
+         </TestableReference>
+      </Testables>
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
+            BuildableName = "InteropTestsRemoteWithCronet.xctest"
+            BlueprintName = "InteropTestsRemoteWithCronet"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Cronet"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
+            BuildableName = "InteropTestsRemoteWithCronet.xctest"
+            BlueprintName = "InteropTestsRemoteWithCronet"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Cronet"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "5EE84BF01D4717E40050C6CC"
+            BuildableName = "InteropTestsRemoteWithCronet.xctest"
+            BlueprintName = "InteropTestsRemoteWithCronet"
+            ReferencedContainer = "container:Tests.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Cronet">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Cronet"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/src/proto/census/census.proto b/src/proto/census/census.proto
index c869d85..c2a594b 100644
--- a/src/proto/census/census.proto
+++ b/src/proto/census/census.proto
@@ -33,12 +33,12 @@
 
 // All the census protos.
 //
-// Nomenclature note: capitalized names below (like Metric) are protos.
+// Nomenclature note: capitalized names below (like Resource) are protos.
 //
-// Census lets you define a Metric - something which can be measured, like the
+// Census lets you define a Resource - something which can be measured, like the
 // latency of an RPC, the number of CPU cycles spent on an operation, or
 // anything else you care to measure. You can record individual instances of
-// measurements (a double value) for every metric of interest. These
+// measurements (a double value) for every Resource of interest. These
 // individual measurements are aggregated together into an Aggregation. There
 // are two Aggregation types available: Distribution (describes the
 // distribution of all measurements, possibly with a histogram) and
@@ -47,8 +47,8 @@
 //
 // You can define how your stats are broken down by Tag values and which
 // Aggregations to use through a View. The corresponding combination of
-// Metric/View/Aggregation which is available to census clients is called a
-// ViewAggregation.
+// Resource/View/Aggregation which is available to census clients is called a
+// Metric.
 
 
 // The following two types are copied from
@@ -85,26 +85,23 @@
   int32 nanos = 2;
 }
 
-// Describes a metric
-message Metric {
-  // name of metric, e.g. rpc_latency, cpu.
+// Describes a Resource.
+message Resource {
+  // name of resource, e.g. rpc_latency, cpu. Must be unique.
   string name = 1;
 
-  // More detailed description of the metric, used in documentation.
+  // More detailed description of the resource, used in documentation.
   string description = 2;
 
   // Fundamental units of measurement supported by Census
   // TODO(aveitch): expand this to include other S.I. units?
-  message BasicUnit {
-    enum Measure {
-      UNKNOWN = 0;
-      BITS = 1;
-      BYTES = 2;
-      SECS = 3;
-      CORES = 4;
-      MAX_UNITS = 5;
-    }
-    Measure type = 1;
+  enum BasicUnit {
+    UNKNOWN = 0;
+    BITS = 1;
+    BYTES = 2;
+    SECS = 3;
+    CORES = 4;
+    MAX_UNITS = 5;
   }
 
   // MeasurementUnit lets you build compound units of the form
@@ -124,7 +121,7 @@
   //     denominator: SECS
   //     denominator: SECS
   //
-  // To specify multiples (in power of 10) units, specify a non-zero prefix
+  // To specify multiples (in power of 10) of units, specify a non-zero prefix
   // value, for example:
   //
   // - MB/s (i.e. megabytes / s):
@@ -141,32 +138,40 @@
     repeated BasicUnit denominator = 3;
   }
 
-  // The units in which the Metric value is reported.
+  // The units in which Resource values are measured.
   MeasurementUnit unit = 3;
-
-  // Metrics will be assigned an ID when registered. Invalid if <= 0.
-  int32 id = 4;
 }
 
-// An Aggregation summarizes a series of individual Metric measurements, an
+// An Aggregation summarizes a series of individual Resource measurements, an
 // AggregationDescriptor describes an Aggregation.
 message AggregationDescriptor {
-  // At most one set of options. If neither option is set, a default type
-  // of Distribution (without a histogram component) will be used.
+  enum AggregationType {
+    // Unspecified. Should not be used.
+    UNKNOWN = 0;
+    // A count of measurements made.
+    COUNT = 1;
+    // A Distribution.
+    DISTRIBUTION = 2;
+    // Counts over fixed time intervals.
+    INTERVAL = 3;
+  }
+  // The type of Aggregation.
+  AggregationType type = 1;
+
+  // At most one set of options. It is illegal to specifiy an option for
+  // COUNT Aggregations. interval_boundaries must be set for INTERVAL types.
+  // bucket_boundaries are optional for DISTRIBUTION types.
   oneof options {
-    // Defines the histogram bucket boundaries for Distributions.
-    BucketBoundaries bucket_boundaries = 1;
+    // Defines histogram bucket boundaries for Distributions.
+    BucketBoundaries bucket_boundaries = 2;
     // Defines the time windows to record for IntervalStats.
-    IntervalBoundaries interval_boundaries = 2;
+    IntervalBoundaries interval_boundaries = 3;
   }
 
   // A Distribution may optionally contain a histogram of the values in the
-  // population. The bucket boundaries for that histogram is described by
-  // `bucket_boundaries`.
-  //
-  // Describes histogram bucket boundaries. Defines `size(bounds) + 1` (= N)
-  // buckets (for size(bounds) >= 1; if size(bounds) == 0, then no histogram
-  // will be defined. The boundaries for bucket index i are:
+  // population. The bucket boundaries for that histogram are described by
+  // `bucket_boundaries`. This defines `size(bounds) + 1` (= N) buckets. The
+  // boundaries for bucket index i are:
   //
   // [-infinity, bounds[i]) for i == 0
   // [bounds[i-1], bounds[i]) for 0 < i < N-2
@@ -196,8 +201,8 @@
 // a specified set of histogram buckets, as defined in
 // Aggregation.bucket_options.
 //
-// The summary statistics are the count, mean, sum of the squared deviation from
-// the mean, the minimum, and the maximum of the set of population of values.
+// The summary statistics are the count, mean, minimum, and the maximum of the
+// set of population of values.
 //
 // Although it is not forbidden, it is generally a bad idea to include
 // non-finite values (infinities or NaNs) in the population of values, as this
@@ -243,7 +248,7 @@
 message IntervalStats {
   // Summary statistic over a single time window.
   message Window {
-    // The window duration.
+    // The window duration. Must be positive.
     Duration window_size = 1;
     // The number of measurements in this window.
     int64 count = 2;
@@ -251,7 +256,7 @@
     double mean = 3;
   }
 
-  // Full set of windows for this metric.
+  // Full set of windows for this aggregation.
   repeated Window window = 1;
 }
 
@@ -264,24 +269,24 @@
 // A View specifies an Aggregation and a set of tag keys. The Aggregation will
 // be broken down by the unique set of matching tag values for each measurement.
 message View {
-  // Name of view.
+  // Name of view. Must be unique.
   string name = 1;
 
   // More detailed description, for documentation purposes.
   string description = 2;
 
-  // ID of Metric to associate with this View.
-  int32 metric_id = 3;
+  // Name of Resource to be broken down for this view.
+  string resource_name = 3;
 
   // Aggregation type to associate with this View.
   AggregationDescriptor aggregation = 4;
 
-  // Tag keys to match with a given Metric. If no keys are specified, then all
-  // stats for the Metric are recorded. Keys must be unique.
+  // Tag keys to match with a given Resource measurement. If no keys are
+  // specified, then all stats are recorded. Keys must be unique.
   repeated string tag_key = 5;
 }
 
-// An Aggregation summarizes a series of individual Metric measures.
+// An Aggregation summarizes a series of individual Resource measurements.
 message Aggregation {
   // Name of this aggregation.
   string name = 1;
@@ -291,23 +296,27 @@
 
   // The data for this Aggregation.
   oneof data {
-    Distribution distribution = 3;
-    IntervalStats interval_stats = 4;
+    uint64 count = 3;
+    Distribution distribution = 4;
+    IntervalStats interval_stats = 5;
   }
 
   // Tags associated with this Aggregation.
-  repeated Tag tag = 5;
+  repeated Tag tag = 6;
 }
 
-// A ViewAggregations represents all the Aggregations for a particular view.
-message ViewAggregations {
+// A Metric represents all the Aggregations for a particular view.
+message Metric {
+  // View associated with this Metric.
+  string view_name = 1;
+
   // Aggregations - each will have a unique set of tag values for the tag_keys
   // associated with the corresponding View.
-  repeated Aggregation aggregation = 1;
+  repeated Aggregation aggregation = 2;
 
-  // Start and end timestamps over which the value was accumulated. These
+  // Start and end timestamps over which the metric was accumulated. These
   // values are not relevant/defined for IntervalStats aggregations, which are
   // always accumulated over a fixed time period.
-  Timestamp start = 2;
-  Timestamp end = 3;
+  Timestamp start = 3;
+  Timestamp end = 4;
 }
diff --git a/src/python/grpcio/.gitignore b/src/python/grpcio/.gitignore
index 7cd8fab..3309795 100644
--- a/src/python/grpcio/.gitignore
+++ b/src/python/grpcio/.gitignore
@@ -14,3 +14,4 @@
 _grpcio_metadata.py
 htmlcov/
 grpc/_cython/_credentials
+poison.c
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 86a73fa..d36ac23 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -184,6 +184,71 @@
     build_py.build_py.run(self)
 
 
+def _poison_extensions(extensions, message):
+  """Includes a file that will always fail to compile in all extensions."""
+  poison_filename = os.path.join(PYTHON_STEM, 'poison.c')
+  with open(poison_filename, 'w') as poison:
+    poison.write('#error {}'.format(message))
+  for extension in extensions:
+    extension.sources = [poison_filename]
+
+def check_and_update_cythonization(extensions):
+  """Replace .pyx files with their generated counterparts and return whether or
+     not cythonization still needs to occur."""
+  for extension in extensions:
+    generated_pyx_sources = []
+    other_sources = []
+    for source in extension.sources:
+      base, file_ext = os.path.splitext(source)
+      if file_ext == '.pyx':
+        generated_pyx_source = next(
+            (base + gen_ext for gen_ext in ('.c', '.cpp',)
+             if os.path.isfile(base + gen_ext)), None)
+        if generated_pyx_source:
+          generated_pyx_sources.append(generated_pyx_source)
+        else:
+          sys.stderr.write('Cython-generated files are missing...\n')
+          return False
+      else:
+        other_sources.append(source)
+    extension.sources = generated_pyx_sources + other_sources
+  sys.stderr.write('Found cython-generated files...\n')
+  return True
+
+def try_cythonize(extensions, linetracing=False, mandatory=True):
+  """Attempt to cythonize the extensions.
+
+  Args:
+    extensions: A list of `distutils.extension.Extension`.
+    linetracing: A bool indicating whether or not to enable linetracing.
+    mandatory: Whether or not having Cython-generated files is mandatory. If it
+      is, extensions will be poisoned when they can't be fully generated.
+  """
+  try:
+    # Break import style to ensure we have access to Cython post-setup_requires
+    import Cython.Build
+  except ImportError:
+    if mandatory:
+      sys.stderr.write(
+          "This package needs to generate C files with Cython but it cannot. "
+          "Poisoning extension sources to disallow extension commands...")
+      _poison_extensions(
+          extensions,
+          "Extensions have been poisoned due to missing Cython-generated code.")
+    return extensions
+  cython_compiler_directives = {}
+  if linetracing:
+    additional_define_macros = [('CYTHON_TRACE_NOGIL', '1')]
+    cython_compiler_directives['linetrace'] = True
+  return Cython.Build.cythonize(
+    extensions,
+    include_path=[
+      include_dir for extension in extensions for include_dir in extension.include_dirs
+    ],
+    compiler_directives=cython_compiler_directives
+  )
+
+
 class BuildExt(build_ext.build_ext):
   """Custom build_ext command to enable compiler-specific flags."""
 
@@ -201,6 +266,8 @@
     if compiler in BuildExt.LINK_OPTIONS:
       for extension in self.extensions:
         extension.extra_link_args += list(BuildExt.LINK_OPTIONS[compiler])
+    if not check_and_update_cythonization(self.extensions):
+      self.extensions = try_cythonize(self.extensions)
     try:
       build_ext.build_ext.build_extensions(self)
     except Exception as error:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
index ba60986..cc3bd7a 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx.pxi
@@ -34,6 +34,7 @@
 
   def __cinit__(self):
     # Create an *empty* call
+    grpc_init()
     self.c_call = NULL
     self.references = []
 
@@ -106,6 +107,7 @@
   def __dealloc__(self):
     if self.c_call != NULL:
       grpc_call_destroy(self.c_call)
+    grpc_shutdown()
 
   # The object *should* always be valid from Python. Used for debugging.
   @property
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index 5416401..3df937e 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -34,6 +34,7 @@
 
   def __cinit__(self, bytes target, ChannelArgs arguments=None,
                 ChannelCredentials channel_credentials=None):
+    grpc_init()
     cdef grpc_channel_args *c_arguments = NULL
     cdef char *c_target = NULL
     self.c_channel = NULL
@@ -103,3 +104,4 @@
   def __dealloc__(self):
     if self.c_channel != NULL:
       grpc_channel_destroy(self.c_channel)
+    grpc_shutdown()
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index 5955021..a258ba4 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -38,6 +38,7 @@
 cdef class CompletionQueue:
 
   def __cinit__(self):
+    grpc_init()
     with nogil:
       self.c_completion_queue = grpc_completion_queue_create(NULL)
     self.is_shutting_down = False
@@ -129,3 +130,4 @@
             self.c_completion_queue, c_deadline, NULL)
         self._interpret_event(event)
       grpc_completion_queue_destroy(self.c_completion_queue)
+    grpc_shutdown()
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 035ac49..04872b9 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -33,6 +33,7 @@
 cdef class ChannelCredentials:
 
   def __cinit__(self):
+    grpc_init()
     self.c_credentials = NULL
     self.c_ssl_pem_key_cert_pair.private_key = NULL
     self.c_ssl_pem_key_cert_pair.certificate_chain = NULL
@@ -47,11 +48,13 @@
   def __dealloc__(self):
     if self.c_credentials != NULL:
       grpc_channel_credentials_release(self.c_credentials)
+    grpc_shutdown()
 
 
 cdef class CallCredentials:
 
   def __cinit__(self):
+    grpc_init()
     self.c_credentials = NULL
     self.references = []
 
@@ -64,17 +67,20 @@
   def __dealloc__(self):
     if self.c_credentials != NULL:
       grpc_call_credentials_release(self.c_credentials)
+    grpc_shutdown()
 
 
 cdef class ServerCredentials:
 
   def __cinit__(self):
+    grpc_init()
     self.c_credentials = NULL
     self.references = []
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
       grpc_server_credentials_release(self.c_credentials)
+    grpc_shutdown()
 
 
 cdef class CredentialsMetadataPlugin:
@@ -90,6 +96,7 @@
         successful).
       name (bytes): Plugin name.
     """
+    grpc_init()
     if not callable(plugin_callback):
       raise ValueError('expected callable plugin_callback')
     self.plugin_callback = plugin_callback
@@ -105,10 +112,14 @@
     cpython.Py_INCREF(self)
     return result
 
+  def __dealloc__(self):
+    grpc_shutdown()
+
 
 cdef class AuthMetadataContext:
 
   def __cinit__(self):
+    grpc_init()
     self.context.service_url = NULL
     self.context.method_name = NULL
 
@@ -120,6 +131,9 @@
   def method_name(self):
     return self.context.method_name
 
+  def __dealloc__(self):
+    grpc_shutdown()
+
 
 cdef void plugin_get_metadata(
     void *state, grpc_auth_metadata_context context,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 54b3d00..834a441 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -176,12 +176,14 @@
 cdef class CallDetails:
 
   def __cinit__(self):
+    grpc_init()
     with nogil:
       grpc_call_details_init(&self.c_details)
 
   def __dealloc__(self):
     with nogil:
       grpc_call_details_destroy(&self.c_details)
+    grpc_shutdown()
 
   @property
   def method(self):
@@ -232,6 +234,7 @@
 cdef class ByteBuffer:
 
   def __cinit__(self, bytes data):
+    grpc_init()
     if data is None:
       self.c_byte_buffer = NULL
       return
@@ -288,6 +291,7 @@
   def __dealloc__(self):
     if self.c_byte_buffer != NULL:
       grpc_byte_buffer_destroy(self.c_byte_buffer)
+    grpc_shutdown()
 
 
 cdef class SslPemKeyCertPair:
@@ -319,6 +323,7 @@
 cdef class ChannelArgs:
 
   def __cinit__(self, args):
+    grpc_init()
     self.args = list(args)
     for arg in self.args:
       if not isinstance(arg, ChannelArg):
@@ -333,6 +338,7 @@
   def __dealloc__(self):
     with nogil:
       gpr_free(self.c_args.arguments)
+    grpc_shutdown()
 
   def __len__(self):
     # self.args is never stale; it's only updated from this file
@@ -399,6 +405,7 @@
 cdef class Metadata:
 
   def __cinit__(self, metadata):
+    grpc_init()
     self.metadata = list(metadata)
     for metadatum in metadata:
       if not isinstance(metadatum, Metadatum):
@@ -420,6 +427,7 @@
     # it'd be nice if that were documented somewhere...)
     # TODO(atash): document this in the C core
     grpc_metadata_array_destroy(&self.c_metadata_array)
+    grpc_shutdown()
 
   def __len__(self):
     return self.c_metadata_array.count
@@ -437,6 +445,7 @@
 cdef class Operation:
 
   def __cinit__(self):
+    grpc_init()
     self.references = []
     self._received_status_details = NULL
     self._received_status_details_capacity = 0
@@ -529,6 +538,7 @@
     # This means that we need to clean up after receive_status_on_client.
     if self.c_op.type == GRPC_OP_RECV_STATUS_ON_CLIENT:
       gpr_free(self._received_status_details)
+    grpc_shutdown()
 
 def operation_send_initial_metadata(Metadata metadata, int flags):
   cdef Operation op = Operation()
@@ -645,6 +655,7 @@
 cdef class Operations:
 
   def __cinit__(self, operations):
+    grpc_init()
     self.operations = list(operations)  # normalize iterable
     self.c_ops = NULL
     self.c_nops = 0
@@ -667,6 +678,7 @@
   def __dealloc__(self):
     with nogil:
       gpr_free(self.c_ops)
+    grpc_shutdown()
 
   def __iter__(self):
     return _OperationsIterator(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index 4f2d51b..ca2b831 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -35,6 +35,7 @@
 cdef class Server:
 
   def __cinit__(self, ChannelArgs arguments=None):
+    grpc_init()
     cdef grpc_channel_args *c_arguments = NULL
     self.references = []
     self.registered_completion_queues = []
@@ -172,3 +173,4 @@
         while not self.is_shutdown:
           time.sleep(0)
       grpc_server_destroy(self.c_server)
+    grpc_shutdown()
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index a9520b9..0808999 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -55,12 +55,8 @@
 
 
 def _initialize():
-  grpc_init()
   grpc_set_ssl_roots_override_callback(
           <grpc_ssl_roots_override_callback>ssl_roots_override_callback)
 
-  if Py_AtExit(grpc_shutdown) != 0:
-    raise ImportError('failed to register gRPC library shutdown callbacks')
-
 
 _initialize()
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index b37e27c..7ae76f5 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -81,6 +81,7 @@
   '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/handshaker.c',
   'src/core/lib/channel/http_client_filter.c',
   'src/core/lib/channel/http_server_filter.c',
   'src/core/lib/compression/compression.c',
@@ -161,6 +162,7 @@
   'src/core/lib/transport/metadata.c',
   'src/core/lib/transport/metadata_batch.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',
@@ -183,7 +185,6 @@
   '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/timeout_encoding.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',
@@ -239,6 +240,7 @@
   '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',
@@ -250,6 +252,7 @@
   '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/grpc_context.c',
@@ -259,6 +262,7 @@
   '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/tracing.c',
   'src/core/plugin_registry/grpc_plugin_registry.c',
   'src/boringssl/err_data.c',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index efa94a0..ea38526 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION='1.0.1rc1'
+VERSION='1.1.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index 082453c..be0d0ce 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION='1.0.1rc1'
+VERSION='1.1.0.dev0'
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index 79c479c..90f68a5 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION='1.0.1rc1'
+VERSION='1.1.0.dev0'
diff --git a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
index 3c00f68..9cae96a 100644
--- a/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
+++ b/src/python/grpcio_tests/tests/unit/_channel_connectivity_test.py
@@ -32,12 +32,12 @@
 import threading
 import time
 import unittest
-from concurrent import futures
 
 import grpc
 from grpc import _channel
 from grpc import _server
 from tests.unit.framework.common import test_constants
+from tests.unit import _thread_pool
 
 
 def _ready_in_connectivities(connectivities):
@@ -104,7 +104,8 @@
         grpc.ChannelConnectivity.READY, fifth_connectivities)
 
   def test_immediately_connectable_channel_connectivity(self):
-    server = _server.Server(futures.ThreadPoolExecutor(max_workers=0), ())
+    thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
+    server = _server.Server(thread_pool, ())
     port = server.add_insecure_port('[::]:0')
     server.start()
     first_callback = _Callback()
@@ -141,9 +142,11 @@
         fourth_connectivities)
     self.assertNotIn(
         grpc.ChannelConnectivity.SHUTDOWN, fourth_connectivities)
+    self.assertFalse(thread_pool.was_used())
 
   def test_reachable_then_unreachable_channel_connectivity(self):
-    server = _server.Server(futures.ThreadPoolExecutor(max_workers=0), ())
+    thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
+    server = _server.Server(thread_pool, ())
     port = server.add_insecure_port('[::]:0')
     server.start()
     callback = _Callback()
@@ -155,6 +158,7 @@
     server.stop(None)
     callback.block_until_connectivities_satisfy(_last_connectivity_is_not_ready)
     channel.unsubscribe(callback.update)
+    self.assertFalse(thread_pool.was_used())
 
 
 if __name__ == '__main__':
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 e8982ed..24f5b45 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
@@ -31,12 +31,12 @@
 
 import threading
 import unittest
-from concurrent import futures
 
 import grpc
 from grpc import _channel
 from grpc import _server
 from tests.unit.framework.common import test_constants
+from tests.unit import _thread_pool
 
 
 class _Callback(object):
@@ -78,7 +78,8 @@
     self.assertFalse(ready_future.running())
 
   def test_immediately_connectable_channel_connectivity(self):
-    server = _server.Server(futures.ThreadPoolExecutor(max_workers=0), ())
+    thread_pool = _thread_pool.RecordingThreadPool(max_workers=None)
+    server = _server.Server(thread_pool, ())
     port = server.add_insecure_port('[::]:0')
     server.start()
     channel = grpc.insecure_channel('localhost:{}'.format(port))
@@ -97,6 +98,7 @@
     self.assertFalse(ready_future.cancelled())
     self.assertTrue(ready_future.done())
     self.assertFalse(ready_future.running())
+    self.assertFalse(thread_pool.was_used())
 
 
 if __name__ == '__main__':
diff --git a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
index f9a8e24..2f50263 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
@@ -30,6 +30,7 @@
 import time
 import threading
 import unittest
+import platform
 
 from grpc._cython import cygrpc
 from tests.unit._cython import test_utilities
@@ -113,6 +114,9 @@
         lambda ignored_a, ignored_b: None, b'')
     del plugin
 
+  @unittest.skipIf(
+    platform.python_implementation() == "PyPy",
+    'TODO(issue 7672): figure out why this fails on PyPy')
   def testCallCredentialsFromPluginUpDown(self):
     plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, b'')
     call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py
index b0d6af7..5a4a328 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_test.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_test.py
@@ -84,6 +84,7 @@
   process.wait()
 
 
+@unittest.skip('https://github.com/grpc/grpc/issues/7311')
 class ExitTest(unittest.TestCase):
 
   def test_unstarted_server(self):
diff --git a/src/python/grpcio_tests/tests/unit/_rpc_test.py b/src/python/grpcio_tests/tests/unit/_rpc_test.py
index 59bf240..ab6546b 100644
--- a/src/python/grpcio_tests/tests/unit/_rpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_rpc_test.py
@@ -233,7 +233,11 @@
             ('test', 'SuccessfulUnaryRequestFutureUnaryResponse'),))
     response = response_future.result()
 
+    self.assertIsInstance(response_future, grpc.Future)
+    self.assertIsInstance(response_future, grpc.Call)
     self.assertEqual(expected_response, response)
+    self.assertIsNone(response_future.exception())
+    self.assertIsNone(response_future.traceback())
 
   def testSuccessfulUnaryRequestStreamResponse(self):
     request = b'\x37\x58'
@@ -287,6 +291,8 @@
     response = response_future.result()
 
     self.assertEqual(expected_response, response)
+    self.assertIsNone(response_future.exception())
+    self.assertIsNone(response_future.traceback())
 
   def testSuccessfulStreamRequestStreamResponse(self):
     requests = tuple(b'\x77\x58' for _ in range(test_constants.STREAM_LENGTH))
@@ -459,6 +465,10 @@
     self.assertTrue(response_future.cancelled())
     with self.assertRaises(grpc.FutureCancelledError):
       response_future.result()
+    with self.assertRaises(grpc.FutureCancelledError):
+      response_future.exception()
+    with self.assertRaises(grpc.FutureCancelledError):
+      response_future.traceback()
     self.assertIs(grpc.StatusCode.CANCELLED, response_future.code())
 
   def testCancelledUnaryRequestStreamResponse(self):
@@ -495,6 +505,10 @@
     self.assertTrue(response_future.cancelled())
     with self.assertRaises(grpc.FutureCancelledError):
       response_future.result()
+    with self.assertRaises(grpc.FutureCancelledError):
+      response_future.exception()
+    with self.assertRaises(grpc.FutureCancelledError):
+      response_future.traceback()
     self.assertIsNotNone(response_future.initial_metadata())
     self.assertIs(grpc.StatusCode.CANCELLED, response_future.code())
     self.assertIsNotNone(response_future.details())
@@ -528,6 +542,7 @@
             request, timeout=test_constants.SHORT_TIMEOUT,
             metadata=(('test', 'ExpiredUnaryRequestBlockingUnaryResponse'),))
 
+    self.assertIsInstance(exception_context.exception, grpc.Call)
     self.assertIsNotNone(exception_context.exception.initial_metadata())
     self.assertIs(
         grpc.StatusCode.DEADLINE_EXCEEDED, exception_context.exception.code())
@@ -556,6 +571,7 @@
     self.assertIs(
         grpc.StatusCode.DEADLINE_EXCEEDED, exception_context.exception.code())
     self.assertIsInstance(response_future.exception(), grpc.RpcError)
+    self.assertIsNotNone(response_future.traceback())
     self.assertIs(
         grpc.StatusCode.DEADLINE_EXCEEDED, response_future.exception().code())
 
@@ -585,6 +601,8 @@
             request_iterator, timeout=test_constants.SHORT_TIMEOUT,
             metadata=(('test', 'ExpiredStreamRequestBlockingUnaryResponse'),))
 
+    self.assertIsInstance(exception_context.exception, grpc.RpcError)
+    self.assertIsInstance(exception_context.exception, grpc.Call)
     self.assertIsNotNone(exception_context.exception.initial_metadata())
     self.assertIs(
         grpc.StatusCode.DEADLINE_EXCEEDED, exception_context.exception.code())
@@ -601,6 +619,8 @@
       response_future = multi_callable.future(
           request_iterator, timeout=test_constants.SHORT_TIMEOUT,
           metadata=(('test', 'ExpiredStreamRequestFutureUnaryResponse'),))
+      with self.assertRaises(grpc.FutureTimeoutError):
+        response_future.result(timeout=test_constants.SHORT_TIMEOUT / 2.0)
       response_future.add_done_callback(callback)
       value_passed_to_callback = callback.value()
 
@@ -610,6 +630,7 @@
     self.assertIs(
         grpc.StatusCode.DEADLINE_EXCEEDED, exception_context.exception.code())
     self.assertIsInstance(response_future.exception(), grpc.RpcError)
+    self.assertIsNotNone(response_future.traceback())
     self.assertIs(response_future, value_passed_to_callback)
     self.assertIsNotNone(response_future.initial_metadata())
     self.assertIs(grpc.StatusCode.DEADLINE_EXCEEDED, response_future.code())
@@ -656,11 +677,14 @@
       response_future.add_done_callback(callback)
       value_passed_to_callback = callback.value()
 
+    self.assertIsInstance(response_future, grpc.Future)
+    self.assertIsInstance(response_future, grpc.Call)
     with self.assertRaises(grpc.RpcError) as exception_context:
       response_future.result()
     self.assertIs(
         grpc.StatusCode.UNKNOWN, exception_context.exception.code())
     self.assertIsInstance(response_future.exception(), grpc.RpcError)
+    self.assertIsNotNone(response_future.traceback())
     self.assertIs(grpc.StatusCode.UNKNOWN, response_future.exception().code())
     self.assertIs(response_future, value_passed_to_callback)
 
@@ -709,6 +733,7 @@
     self.assertIs(
         grpc.StatusCode.UNKNOWN, exception_context.exception.code())
     self.assertIsInstance(response_future.exception(), grpc.RpcError)
+    self.assertIsNotNone(response_future.traceback())
     self.assertIs(response_future, value_passed_to_callback)
 
   def testFailedStreamRequestStreamResponse(self):
diff --git a/src/python/grpcio_tests/tests/unit/_thread_pool.py b/src/python/grpcio_tests/tests/unit/_thread_pool.py
new file mode 100644
index 0000000..f13cc2f
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_thread_pool.py
@@ -0,0 +1,48 @@
+# 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 threading
+from concurrent import futures
+
+
+class RecordingThreadPool(futures.Executor):
+  """A thread pool that records if used."""
+  def __init__(self, max_workers):
+    self._tp_executor = futures.ThreadPoolExecutor(max_workers=max_workers)
+    self._lock = threading.Lock()
+    self._was_used = False
+
+  def submit(self, fn, *args, **kwargs):
+    with self._lock:
+      self._was_used = True
+    self._tp_executor.submit(fn, *args, **kwargs)
+
+  def was_used(self):
+    with self._lock:
+      return self._was_used
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 2126124..67a42af 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -38,6 +38,7 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
+#include <grpc/impl/codegen/compression_types.h>
 
 #include "rb_byte_buffer.h"
 #include "rb_call_credentials.h"
@@ -910,6 +911,12 @@
                   UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER));
 }
 
+static void Init_grpc_metadata_keys() {
+  VALUE grpc_rb_mMetadataKeys = rb_define_module_under(grpc_rb_mGrpcCore, "MetadataKeys");
+  rb_define_const(grpc_rb_mMetadataKeys, "COMPRESSION_REQUEST_ALGORITHM",
+                  rb_str_new2(GRPC_COMPRESSION_REQUEST_ALGORITHM_MD_KEY));
+}
+
 void Init_grpc_call() {
   /* CallError inherits from Exception to signal that it is non-recoverable */
   grpc_rb_eCallError =
@@ -972,6 +979,7 @@
   Init_grpc_error_codes();
   Init_grpc_op_codes();
   Init_grpc_write_flags();
+  Init_grpc_metadata_keys();
 }
 
 /* Gets the call from the ruby object */
diff --git a/src/ruby/ext/grpc/rb_compression_options.c b/src/ruby/ext/grpc/rb_compression_options.c
new file mode 100644
index 0000000..0a3a215
--- /dev/null
+++ b/src/ruby/ext/grpc/rb_compression_options.c
@@ -0,0 +1,464 @@
+/*
+ *
+ * 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 <ruby/ruby.h>
+
+#include "rb_compression_options.h"
+#include "rb_grpc_imports.generated.h"
+
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <string.h>
+
+#include "rb_grpc.h"
+
+static VALUE grpc_rb_cCompressionOptions = Qnil;
+
+/* Ruby Ids for the names of valid compression levels. */
+static VALUE id_compress_level_none = Qnil;
+static VALUE id_compress_level_low = Qnil;
+static VALUE id_compress_level_medium = Qnil;
+static VALUE id_compress_level_high = Qnil;
+
+/* grpc_rb_compression_options wraps a grpc_compression_options.
+ * It can be used to get the channel argument key-values for specific
+ * compression settings. */
+
+/* Note that ruby objects of this type don't carry any state in other
+ * Ruby objects and don't have a mark for GC. */
+typedef struct grpc_rb_compression_options {
+  /* The actual compression options that's being wrapped */
+  grpc_compression_options *wrapped;
+} grpc_rb_compression_options;
+
+/* Destroys the compression options instances and free the
+ * wrapped grpc compression options. */
+static void grpc_rb_compression_options_free(void *p) {
+  grpc_rb_compression_options *wrapper = NULL;
+  if (p == NULL) {
+    return;
+  };
+  wrapper = (grpc_rb_compression_options *)p;
+
+  if (wrapper->wrapped != NULL) {
+    gpr_free(wrapper->wrapped);
+    wrapper->wrapped = NULL;
+  }
+
+  xfree(p);
+}
+
+/* Ruby recognized data type for the CompressionOptions class. */
+static rb_data_type_t grpc_rb_compression_options_data_type = {
+    "grpc_compression_options",
+    {NULL,
+     grpc_rb_compression_options_free,
+     GRPC_RB_MEMSIZE_UNAVAILABLE,
+     {NULL, NULL}},
+    NULL,
+    NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+    RUBY_TYPED_FREE_IMMEDIATELY
+#endif
+};
+
+/* Allocates CompressionOptions instances.
+   Allocate the wrapped grpc compression options and
+   initialize it here too. */
+static VALUE grpc_rb_compression_options_alloc(VALUE cls) {
+  grpc_rb_compression_options *wrapper =
+      gpr_malloc(sizeof(grpc_rb_compression_options));
+  wrapper->wrapped = NULL;
+  wrapper->wrapped = gpr_malloc(sizeof(grpc_compression_options));
+  grpc_compression_options_init(wrapper->wrapped);
+
+  return TypedData_Wrap_Struct(cls, &grpc_rb_compression_options_data_type,
+                               wrapper);
+}
+
+/* Disables a compression algorithm, given the GRPC core internal number of a
+ * compression algorithm. */
+VALUE grpc_rb_compression_options_disable_compression_algorithm_internal(
+    VALUE self, VALUE algorithm_to_disable) {
+  grpc_compression_algorithm compression_algorithm = 0;
+  grpc_rb_compression_options *wrapper = NULL;
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+  compression_algorithm =
+      (grpc_compression_algorithm)NUM2INT(algorithm_to_disable);
+
+  grpc_compression_options_disable_algorithm(wrapper->wrapped,
+                                             compression_algorithm);
+
+  return Qnil;
+}
+
+/* Gets the compression internal enum value of a compression level given its
+ * name. */
+grpc_compression_level grpc_rb_compression_options_level_name_to_value_internal(
+    VALUE level_name) {
+  Check_Type(level_name, T_SYMBOL);
+
+  /* Check the compression level of the name passed in, and see which macro
+   * from the GRPC core header files match. */
+  if (id_compress_level_none == SYM2ID(level_name)) {
+    return GRPC_COMPRESS_LEVEL_NONE;
+  } else if (id_compress_level_low == SYM2ID(level_name)) {
+    return GRPC_COMPRESS_LEVEL_LOW;
+  } else if (id_compress_level_medium == SYM2ID(level_name)) {
+    return GRPC_COMPRESS_LEVEL_MED;
+  } else if (id_compress_level_high == SYM2ID(level_name)) {
+    return GRPC_COMPRESS_LEVEL_HIGH;
+  }
+
+  rb_raise(rb_eArgError,
+           "Unrecognized compression level name."
+           "Valid compression level names are none, low, medium, and high.");
+
+  /* Dummy return statement. */
+  return GRPC_COMPRESS_LEVEL_NONE;
+}
+
+/* Sets the default compression level, given the name of a compression level.
+ * Throws an error if no algorithm matched. */
+void grpc_rb_compression_options_set_default_level(
+    grpc_compression_options *options, VALUE new_level_name) {
+  options->default_level.level =
+      grpc_rb_compression_options_level_name_to_value_internal(new_level_name);
+  options->default_level.is_set = 1;
+}
+
+/* Gets the internal value of a compression algorithm suitable as the value
+ * in a GRPC core channel arguments hash.
+ * algorithm_value is an out parameter.
+ * Raises an error if the name of the algorithm passed in is invalid. */
+void grpc_rb_compression_options_algorithm_name_to_value_internal(
+    grpc_compression_algorithm *algorithm_value, VALUE algorithm_name) {
+  char *name_str = NULL;
+  long name_len = 0;
+  VALUE algorithm_name_as_string = Qnil;
+
+  Check_Type(algorithm_name, T_SYMBOL);
+
+  /* Convert the algorithm symbol to a ruby string, so that we can get the
+   * correct C string out of it. */
+  algorithm_name_as_string = rb_funcall(algorithm_name, rb_intern("to_s"), 0);
+
+  name_str = RSTRING_PTR(algorithm_name_as_string);
+  name_len = RSTRING_LEN(algorithm_name_as_string);
+
+  /* Raise an error if the name isn't recognized as a compression algorithm by
+   * the algorithm parse function
+   * in GRPC core. */
+  if (!grpc_compression_algorithm_parse(name_str, name_len, algorithm_value)) {
+    rb_raise(rb_eNameError, "Invalid compression algorithm name: %s",
+             StringValueCStr(algorithm_name_as_string));
+  }
+}
+
+/* Indicates whether a given algorithm is enabled on this instance, given the
+ * readable algorithm name. */
+VALUE grpc_rb_compression_options_is_algorithm_enabled(VALUE self,
+                                                       VALUE algorithm_name) {
+  grpc_rb_compression_options *wrapper = NULL;
+  grpc_compression_algorithm internal_algorithm_value;
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+  grpc_rb_compression_options_algorithm_name_to_value_internal(
+      &internal_algorithm_value, algorithm_name);
+
+  if (grpc_compression_options_is_algorithm_enabled(wrapper->wrapped,
+                                                    internal_algorithm_value)) {
+    return Qtrue;
+  }
+  return Qfalse;
+}
+
+/* Sets the default algorithm to the name of the algorithm passed in.
+ * Raises an error if the name is not a valid compression algorithm name. */
+void grpc_rb_compression_options_set_default_algorithm(
+    grpc_compression_options *options, VALUE algorithm_name) {
+  grpc_rb_compression_options_algorithm_name_to_value_internal(
+      &options->default_algorithm.algorithm, algorithm_name);
+  options->default_algorithm.is_set = 1;
+}
+
+/* Disables an algorithm on the current instance, given the name of an
+ * algorithm.
+ * Fails if the algorithm name is invalid. */
+void grpc_rb_compression_options_disable_algorithm(
+    grpc_compression_options *compression_options, VALUE algorithm_name) {
+  grpc_compression_algorithm internal_algorithm_value;
+
+  grpc_rb_compression_options_algorithm_name_to_value_internal(
+      &internal_algorithm_value, algorithm_name);
+  grpc_compression_options_disable_algorithm(compression_options,
+                                             internal_algorithm_value);
+}
+
+/* Provides a ruby hash of GRPC core channel argument key-values that
+ * correspond to the compression settings on this instance. */
+VALUE grpc_rb_compression_options_to_hash(VALUE self) {
+  grpc_rb_compression_options *wrapper = NULL;
+  grpc_compression_options *compression_options = NULL;
+  VALUE channel_arg_hash = rb_hash_new();
+  VALUE key = Qnil;
+  VALUE value = Qnil;
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+  compression_options = wrapper->wrapped;
+
+  /* Add key-value pairs to the new Ruby hash. It can be used
+   * as GRPC core channel arguments. */
+  if (compression_options->default_level.is_set) {
+    key = rb_str_new2(GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL);
+    value = INT2NUM((int)compression_options->default_level.level);
+    rb_hash_aset(channel_arg_hash, key, value);
+  }
+
+  if (compression_options->default_algorithm.is_set) {
+    key = rb_str_new2(GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM);
+    value = INT2NUM((int)compression_options->default_algorithm.algorithm);
+    rb_hash_aset(channel_arg_hash, key, value);
+  }
+
+  key = rb_str_new2(GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET);
+  value = INT2NUM((int)compression_options->enabled_algorithms_bitset);
+  rb_hash_aset(channel_arg_hash, key, value);
+
+  return channel_arg_hash;
+}
+
+/* Converts an internal enum level value to a readable level name.
+ * Fails if the level value is invalid. */
+VALUE grpc_rb_compression_options_level_value_to_name_internal(
+    grpc_compression_level compression_value) {
+  switch (compression_value) {
+    case GRPC_COMPRESS_LEVEL_NONE:
+      return ID2SYM(id_compress_level_none);
+    case GRPC_COMPRESS_LEVEL_LOW:
+      return ID2SYM(id_compress_level_low);
+    case GRPC_COMPRESS_LEVEL_MED:
+      return ID2SYM(id_compress_level_medium);
+    case GRPC_COMPRESS_LEVEL_HIGH:
+      return ID2SYM(id_compress_level_high);
+    default:
+      rb_raise(
+          rb_eArgError,
+          "Failed to convert compression level value to name for value: %d",
+          (int)compression_value);
+  }
+}
+
+/* Converts an algorithm internal enum value to a readable name.
+ * Fails if the enum value is invalid. */
+VALUE grpc_rb_compression_options_algorithm_value_to_name_internal(
+    grpc_compression_algorithm internal_value) {
+  char *algorithm_name = NULL;
+
+  if (!grpc_compression_algorithm_name(internal_value, &algorithm_name)) {
+    rb_raise(rb_eArgError, "Failed to convert algorithm value to name");
+  }
+
+  return ID2SYM(rb_intern(algorithm_name));
+}
+
+/* Gets the readable name of the default algorithm if one has been set.
+ * Returns nil if no algorithm has been set. */
+VALUE grpc_rb_compression_options_get_default_algorithm(VALUE self) {
+  grpc_compression_algorithm internal_value;
+  grpc_rb_compression_options *wrapper = NULL;
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+
+  if (wrapper->wrapped->default_algorithm.is_set) {
+    internal_value = wrapper->wrapped->default_algorithm.algorithm;
+    return grpc_rb_compression_options_algorithm_value_to_name_internal(
+        internal_value);
+  }
+
+  return Qnil;
+}
+
+/* Gets the internal value of the default compression level that is to be passed
+ * to the GRPC core as a channel argument value.
+ * A nil return value means that it hasn't been set. */
+VALUE grpc_rb_compression_options_get_default_level(VALUE self) {
+  grpc_compression_level internal_value;
+  grpc_rb_compression_options *wrapper = NULL;
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+
+  if (wrapper->wrapped->default_level.is_set) {
+    internal_value = wrapper->wrapped->default_level.level;
+    return grpc_rb_compression_options_level_value_to_name_internal(
+        internal_value);
+  }
+
+  return Qnil;
+}
+
+/* Gets a list of the disabled algorithms as readable names.
+ * Returns an empty list if no algorithms have been disabled. */
+VALUE grpc_rb_compression_options_get_disabled_algorithms(VALUE self) {
+  VALUE disabled_algorithms = rb_ary_new();
+  grpc_compression_algorithm internal_value;
+  grpc_rb_compression_options *wrapper = NULL;
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+
+  for (internal_value = GRPC_COMPRESS_NONE;
+       internal_value < GRPC_COMPRESS_ALGORITHMS_COUNT; internal_value++) {
+    if (!grpc_compression_options_is_algorithm_enabled(wrapper->wrapped,
+                                                       internal_value)) {
+      rb_ary_push(disabled_algorithms,
+                  grpc_rb_compression_options_algorithm_value_to_name_internal(
+                      internal_value));
+    }
+  }
+  return disabled_algorithms;
+}
+
+/* Initializes the compression options wrapper.
+ * Takes an optional hash parameter.
+ *
+ * Example call-seq:
+ *   options = CompressionOptions.new(
+ *     default_level: :none,
+ *     disabled_algorithms: [:gzip]
+ *   )
+ *   channel_arg hash = Hash.new[...]
+ *   channel_arg_hash_with_compression_options = channel_arg_hash.merge(options)
+ */
+VALUE grpc_rb_compression_options_init(int argc, VALUE *argv, VALUE self) {
+  grpc_rb_compression_options *wrapper = NULL;
+  VALUE default_algorithm = Qnil;
+  VALUE default_level = Qnil;
+  VALUE disabled_algorithms = Qnil;
+  VALUE algorithm_name = Qnil;
+  VALUE hash_arg = Qnil;
+
+  rb_scan_args(argc, argv, "01", &hash_arg);
+
+  /* Check if the hash parameter was passed, or if invalid arguments were
+   * passed. */
+  if (hash_arg == Qnil) {
+    return self;
+  } else if (TYPE(hash_arg) != T_HASH || argc > 1) {
+    rb_raise(rb_eArgError,
+             "Invalid arguments. Expecting optional hash parameter");
+  }
+
+  TypedData_Get_Struct(self, grpc_rb_compression_options,
+                       &grpc_rb_compression_options_data_type, wrapper);
+
+  /* Set the default algorithm if one was chosen. */
+  default_algorithm =
+      rb_hash_aref(hash_arg, ID2SYM(rb_intern("default_algorithm")));
+  if (default_algorithm != Qnil) {
+    grpc_rb_compression_options_set_default_algorithm(wrapper->wrapped,
+                                                      default_algorithm);
+  }
+
+  /* Set the default level if one was chosen. */
+  default_level = rb_hash_aref(hash_arg, ID2SYM(rb_intern("default_level")));
+  if (default_level != Qnil) {
+    grpc_rb_compression_options_set_default_level(wrapper->wrapped,
+                                                  default_level);
+  }
+
+  /* Set the disabled algorithms if any were chosen. */
+  disabled_algorithms =
+      rb_hash_aref(hash_arg, ID2SYM(rb_intern("disabled_algorithms")));
+  if (disabled_algorithms != Qnil) {
+    Check_Type(disabled_algorithms, T_ARRAY);
+
+    for (int i = 0; i < RARRAY_LEN(disabled_algorithms); i++) {
+      algorithm_name = rb_ary_entry(disabled_algorithms, i);
+      grpc_rb_compression_options_disable_algorithm(wrapper->wrapped,
+                                                    algorithm_name);
+    }
+  }
+
+  return self;
+}
+
+void Init_grpc_compression_options() {
+  grpc_rb_cCompressionOptions = rb_define_class_under(
+      grpc_rb_mGrpcCore, "CompressionOptions", rb_cObject);
+
+  /* Allocates an object managed by the ruby runtime. */
+  rb_define_alloc_func(grpc_rb_cCompressionOptions,
+                       grpc_rb_compression_options_alloc);
+
+  /* Initializes the ruby wrapper. #new method takes an optional hash argument.
+   */
+  rb_define_method(grpc_rb_cCompressionOptions, "initialize",
+                   grpc_rb_compression_options_init, -1);
+
+  /* Methods for getting the default algorithm, default level, and disabled
+   * algorithms as readable names. */
+  rb_define_method(grpc_rb_cCompressionOptions, "default_algorithm",
+                   grpc_rb_compression_options_get_default_algorithm, 0);
+  rb_define_method(grpc_rb_cCompressionOptions, "default_level",
+                   grpc_rb_compression_options_get_default_level, 0);
+  rb_define_method(grpc_rb_cCompressionOptions, "disabled_algorithms",
+                   grpc_rb_compression_options_get_disabled_algorithms, 0);
+
+  /* Determines whether or not an algorithm is enabled, given a readable
+   * algorithm name.*/
+  rb_define_method(grpc_rb_cCompressionOptions, "algorithm_enabled?",
+                   grpc_rb_compression_options_is_algorithm_enabled, 1);
+
+  /* Provides a hash of the compression settings suitable
+   * for passing to server or channel args. */
+  rb_define_method(grpc_rb_cCompressionOptions, "to_hash",
+                   grpc_rb_compression_options_to_hash, 0);
+  rb_define_alias(grpc_rb_cCompressionOptions, "to_channel_arg_hash",
+                  "to_hash");
+
+  /* Ruby ids for the names of the different compression levels. */
+  id_compress_level_none = rb_intern("none");
+  id_compress_level_low = rb_intern("low");
+  id_compress_level_medium = rb_intern("medium");
+  id_compress_level_high = rb_intern("high");
+}
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/src/ruby/ext/grpc/rb_compression_options.h
similarity index 71%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to src/ruby/ext/grpc/rb_compression_options.h
index df2324c..4d5a924 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/src/ruby/ext/grpc/rb_compression_options.h
@@ -31,17 +31,14 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#ifndef GRPC_RB_COMPRESSION_OPTIONS_H_
+#define GRPC_RB_COMPRESSION_OPTIONS_H_
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#include <ruby/ruby.h>
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+#include <grpc/grpc.h>
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+/* Initializes the compression options ruby wrapper. */
+void Init_grpc_compression_options();
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+#endif /* GRPC_RB_COMPRESSION_OPTIONS_H_ */
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 188a624..17cd165 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -49,6 +49,7 @@
 #include "rb_loader.h"
 #include "rb_server.h"
 #include "rb_server_credentials.h"
+#include "rb_compression_options.h"
 
 static VALUE grpc_rb_cTimeVal = Qnil;
 
@@ -220,7 +221,7 @@
                        time_const);
   real_time = gpr_convert_clock_type(*time_const, GPR_CLOCK_REALTIME);
   return rb_funcall(rb_cTime, id_at, 2, INT2NUM(real_time.tv_sec),
-                    INT2NUM(real_time.tv_nsec));
+                    INT2NUM(real_time.tv_nsec / 1000));
 }
 
 /* Invokes inspect on the ctime version of the time val. */
@@ -332,4 +333,5 @@
   Init_grpc_server_credentials();
   Init_grpc_status_codes();
   Init_grpc_time_consts();
+  Init_grpc_compression_options();
 }
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 9748cb5..aee57b1 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -61,15 +61,10 @@
 census_trace_scan_start_type census_trace_scan_start_import;
 census_get_trace_record_type census_get_trace_record_import;
 census_trace_scan_end_type census_trace_scan_end_import;
+census_define_resource_type census_define_resource_import;
+census_delete_resource_type census_delete_resource_import;
+census_resource_id_type census_resource_id_import;
 census_record_values_type census_record_values_import;
-census_view_create_type census_view_create_import;
-census_view_delete_type census_view_delete_import;
-census_view_metric_type census_view_metric_import;
-census_view_naggregations_type census_view_naggregations_import;
-census_view_tags_type census_view_tags_import;
-census_view_aggregrations_type census_view_aggregrations_import;
-census_view_get_data_type census_view_get_data_import;
-census_view_reset_type census_view_reset_import;
 grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_import;
 grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
 grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
@@ -186,6 +181,7 @@
 gpr_slice_ref_type gpr_slice_ref_import;
 gpr_slice_unref_type gpr_slice_unref_import;
 gpr_slice_new_type gpr_slice_new_import;
+gpr_slice_new_with_user_data_type gpr_slice_new_with_user_data_import;
 gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
 gpr_slice_malloc_type gpr_slice_malloc_import;
 gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
@@ -333,15 +329,10 @@
   census_trace_scan_start_import = (census_trace_scan_start_type) GetProcAddress(library, "census_trace_scan_start");
   census_get_trace_record_import = (census_get_trace_record_type) GetProcAddress(library, "census_get_trace_record");
   census_trace_scan_end_import = (census_trace_scan_end_type) GetProcAddress(library, "census_trace_scan_end");
+  census_define_resource_import = (census_define_resource_type) GetProcAddress(library, "census_define_resource");
+  census_delete_resource_import = (census_delete_resource_type) GetProcAddress(library, "census_delete_resource");
+  census_resource_id_import = (census_resource_id_type) GetProcAddress(library, "census_resource_id");
   census_record_values_import = (census_record_values_type) GetProcAddress(library, "census_record_values");
-  census_view_create_import = (census_view_create_type) GetProcAddress(library, "census_view_create");
-  census_view_delete_import = (census_view_delete_type) GetProcAddress(library, "census_view_delete");
-  census_view_metric_import = (census_view_metric_type) GetProcAddress(library, "census_view_metric");
-  census_view_naggregations_import = (census_view_naggregations_type) GetProcAddress(library, "census_view_naggregations");
-  census_view_tags_import = (census_view_tags_type) GetProcAddress(library, "census_view_tags");
-  census_view_aggregrations_import = (census_view_aggregrations_type) GetProcAddress(library, "census_view_aggregrations");
-  census_view_get_data_import = (census_view_get_data_type) GetProcAddress(library, "census_view_get_data");
-  census_view_reset_import = (census_view_reset_type) GetProcAddress(library, "census_view_reset");
   grpc_compression_algorithm_parse_import = (grpc_compression_algorithm_parse_type) GetProcAddress(library, "grpc_compression_algorithm_parse");
   grpc_compression_algorithm_name_import = (grpc_compression_algorithm_name_type) GetProcAddress(library, "grpc_compression_algorithm_name");
   grpc_compression_algorithm_for_level_import = (grpc_compression_algorithm_for_level_type) GetProcAddress(library, "grpc_compression_algorithm_for_level");
@@ -458,6 +449,7 @@
   gpr_slice_ref_import = (gpr_slice_ref_type) GetProcAddress(library, "gpr_slice_ref");
   gpr_slice_unref_import = (gpr_slice_unref_type) GetProcAddress(library, "gpr_slice_unref");
   gpr_slice_new_import = (gpr_slice_new_type) GetProcAddress(library, "gpr_slice_new");
+  gpr_slice_new_with_user_data_import = (gpr_slice_new_with_user_data_type) GetProcAddress(library, "gpr_slice_new_with_user_data");
   gpr_slice_new_with_len_import = (gpr_slice_new_with_len_type) GetProcAddress(library, "gpr_slice_new_with_len");
   gpr_slice_malloc_import = (gpr_slice_malloc_type) GetProcAddress(library, "gpr_slice_malloc");
   gpr_slice_from_copied_string_import = (gpr_slice_from_copied_string_type) GetProcAddress(library, "gpr_slice_from_copied_string");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 6f0974e..3bb76fb 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -134,33 +134,18 @@
 typedef void(*census_trace_scan_end_type)();
 extern census_trace_scan_end_type census_trace_scan_end_import;
 #define census_trace_scan_end census_trace_scan_end_import
+typedef int32_t(*census_define_resource_type)(const uint8_t *resource_pb, size_t resource_pb_size);
+extern census_define_resource_type census_define_resource_import;
+#define census_define_resource census_define_resource_import
+typedef void(*census_delete_resource_type)(int32_t resource_id);
+extern census_delete_resource_type census_delete_resource_import;
+#define census_delete_resource census_delete_resource_import
+typedef int32_t(*census_resource_id_type)(const char *name);
+extern census_resource_id_type census_resource_id_import;
+#define census_resource_id census_resource_id_import
 typedef void(*census_record_values_type)(census_context *context, census_value *values, size_t nvalues);
 extern census_record_values_type census_record_values_import;
 #define census_record_values census_record_values_import
-typedef census_view *(*census_view_create_type)(uint32_t metric_id, const census_context *tags, const census_aggregation *aggregations, size_t naggregations);
-extern census_view_create_type census_view_create_import;
-#define census_view_create census_view_create_import
-typedef void(*census_view_delete_type)(census_view *view);
-extern census_view_delete_type census_view_delete_import;
-#define census_view_delete census_view_delete_import
-typedef size_t(*census_view_metric_type)(const census_view *view);
-extern census_view_metric_type census_view_metric_import;
-#define census_view_metric census_view_metric_import
-typedef size_t(*census_view_naggregations_type)(const census_view *view);
-extern census_view_naggregations_type census_view_naggregations_import;
-#define census_view_naggregations census_view_naggregations_import
-typedef const census_context *(*census_view_tags_type)(const census_view *view);
-extern census_view_tags_type census_view_tags_import;
-#define census_view_tags census_view_tags_import
-typedef const census_aggregation *(*census_view_aggregrations_type)(const census_view *view);
-extern census_view_aggregrations_type census_view_aggregrations_import;
-#define census_view_aggregrations census_view_aggregrations_import
-typedef const census_view_data *(*census_view_get_data_type)(const census_view *view);
-extern census_view_get_data_type census_view_get_data_import;
-#define census_view_get_data census_view_get_data_import
-typedef void(*census_view_reset_type)(census_view *view);
-extern census_view_reset_type census_view_reset_import;
-#define census_view_reset census_view_reset_import
 typedef int(*grpc_compression_algorithm_parse_type)(const char *name, size_t name_length, grpc_compression_algorithm *algorithm);
 extern grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_import;
 #define grpc_compression_algorithm_parse grpc_compression_algorithm_parse_import
@@ -509,6 +494,9 @@
 typedef gpr_slice(*gpr_slice_new_type)(void *p, size_t len, void (*destroy)(void *));
 extern gpr_slice_new_type gpr_slice_new_import;
 #define gpr_slice_new gpr_slice_new_import
+typedef gpr_slice(*gpr_slice_new_with_user_data_type)(void *p, size_t len, void (*destroy)(void *), void *user_data);
+extern gpr_slice_new_with_user_data_type gpr_slice_new_with_user_data_import;
+#define gpr_slice_new_with_user_data gpr_slice_new_with_user_data_import
 typedef gpr_slice(*gpr_slice_new_with_len_type)(void *p, size_t len, void (*destroy)(void *, size_t));
 extern gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
 #define gpr_slice_new_with_len gpr_slice_new_with_len_import
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index bf26841..2a6a246 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -218,7 +218,7 @@
       grpc_rb_sNewServerRpc, rb_str_new2(st.details.method),
       rb_str_new2(st.details.host),
       rb_funcall(rb_cTime, id_at, 2, INT2NUM(deadline.tv_sec),
-                 INT2NUM(deadline.tv_nsec)),
+                 INT2NUM(deadline.tv_nsec / 1000)),
       grpc_rb_md_ary_to_h(&st.md_ary), grpc_rb_wrap_call(call, call_queue),
       NULL);
   grpc_request_call_stack_cleanup(&st);
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 4260d85..23688dc 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -58,7 +58,7 @@
     include Core::TimeConsts
     include Core::CallOps
     extend Forwardable
-    attr_reader(:deadline)
+    attr_reader :deadline, :metadata_sent, :metadata_to_send
     def_delegators :@call, :cancel, :metadata, :write_flag, :write_flag=,
                    :peer, :peer_cert, :trailing_metadata
 
@@ -101,7 +101,7 @@
     # @param metadata_received [true|false] indicates if metadata has already
     #     been received. Should always be true for server calls
     def initialize(call, marshal, unmarshal, deadline, started: true,
-                   metadata_received: false)
+                   metadata_received: false, metadata_to_send: nil)
       fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
       @call = call
       @deadline = deadline
@@ -110,6 +110,20 @@
       @metadata_received = metadata_received
       @metadata_sent = started
       @op_notifier = nil
+
+      fail(ArgumentError, 'Already sent md') if started && metadata_to_send
+      @metadata_to_send = metadata_to_send || {} unless started
+      @send_initial_md_mutex = Mutex.new
+    end
+
+    # Sends the initial metadata that has yet to be sent.
+    # Does nothing if metadata has already been sent for this call.
+    def send_initial_metadata
+      @send_initial_md_mutex.synchronize do
+        return if @metadata_sent
+        @metadata_tag = ActiveCall.client_invoke(@call, @metadata_to_send)
+        @metadata_sent = true
+      end
     end
 
     # output_metadata are provides access to hash that can be used to
@@ -187,7 +201,7 @@
     # @param marshalled [false, true] indicates if the object is already
     # marshalled.
     def remote_send(req, marshalled = false)
-      # TODO(murgatroid99): ensure metadata was sent
+      send_initial_metadata
       GRPC.logger.debug("sending #{req}, marshalled? #{marshalled}")
       payload = marshalled ? req : @marshal.call(req)
       @call.run_batch(SEND_MESSAGE => payload)
@@ -203,6 +217,7 @@
     # list, mulitple metadata for its key are sent
     def send_status(code = OK, details = '', assert_finished = false,
                     metadata: {})
+      send_initial_metadata
       ops = {
         SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details, metadata)
       }
@@ -303,7 +318,7 @@
     # a list, multiple metadata for its key are sent
     # @return [Object] the response received from the server
     def request_response(req, metadata: {})
-      start_call(metadata)
+      merge_metadata_to_send(metadata) && send_initial_metadata
       remote_send(req)
       writes_done(false)
       response = remote_read
@@ -327,7 +342,7 @@
     # a list, multiple metadata for its key are sent
     # @return [Object] the response received from the server
     def client_streamer(requests, metadata: {})
-      start_call(metadata)
+      merge_metadata_to_send(metadata) && send_initial_metadata
       requests.each { |r| remote_send(r) }
       writes_done(false)
       response = remote_read
@@ -353,7 +368,7 @@
     # a list, multiple metadata for its key are sent
     # @return [Enumerator|nil] a response Enumerator
     def server_streamer(req, metadata: {})
-      start_call(metadata)
+      merge_metadata_to_send(metadata) && send_initial_metadata
       remote_send(req)
       writes_done(false)
       replies = enum_for(:each_remote_read_then_finish)
@@ -392,9 +407,12 @@
     # a list, multiple metadata for its key are sent
     # @return [Enumerator, nil] a response Enumerator
     def bidi_streamer(requests, metadata: {}, &blk)
-      start_call(metadata)
-      bd = BidiCall.new(@call, @marshal, @unmarshal,
+      merge_metadata_to_send(metadata) && send_initial_metadata
+      bd = BidiCall.new(@call,
+                        @marshal,
+                        @unmarshal,
                         metadata_received: @metadata_received)
+
       bd.run_on_client(requests, @op_notifier, &blk)
     end
 
@@ -410,8 +428,12 @@
     #
     # @param gen_each_reply [Proc] generates the BiDi stream replies
     def run_server_bidi(gen_each_reply)
-      bd = BidiCall.new(@call, @marshal, @unmarshal,
-                        metadata_received: @metadata_received)
+      bd = BidiCall.new(@call,
+                        @marshal,
+                        @unmarshal,
+                        metadata_received: @metadata_received,
+                        req_view: MultiReqView.new(self))
+
       bd.run_on_server(gen_each_reply)
     end
 
@@ -428,15 +450,23 @@
       @op_notifier.notify(self)
     end
 
+    # Add to the metadata that will be sent from the server.
+    # Fails if metadata has already been sent.
+    # Unused by client calls.
+    def merge_metadata_to_send(new_metadata = {})
+      @send_initial_md_mutex.synchronize do
+        fail('cant change metadata after already sent') if @metadata_sent
+        @metadata_to_send.merge!(new_metadata)
+      end
+    end
+
     private
 
     # Starts the call if not already started
     # @param metadata [Hash] metadata to be sent to the server. If a value is
     # a list, multiple metadata for its key are sent
     def start_call(metadata = {})
-      return if @metadata_sent
-      @metadata_tag = ActiveCall.client_invoke(@call, metadata)
-      @metadata_sent = true
+      merge_metadata_to_send(metadata) && send_initial_metadata
     end
 
     def self.view_class(*visible_methods)
@@ -454,12 +484,20 @@
     # SingleReqView limits access to an ActiveCall's methods for use in server
     # handlers that receive just one request.
     SingleReqView = view_class(:cancelled?, :deadline, :metadata,
-                               :output_metadata, :peer, :peer_cert)
+                               :output_metadata, :peer, :peer_cert,
+                               :send_initial_metadata,
+                               :metadata_to_send,
+                               :merge_metadata_to_send,
+                               :metadata_sent)
 
     # MultiReqView limits access to an ActiveCall's methods for use in
     # server client_streamer handlers.
     MultiReqView = view_class(:cancelled?, :deadline, :each_queued_msg,
-                              :each_remote_read, :metadata, :output_metadata)
+                              :each_remote_read, :metadata, :output_metadata,
+                              :send_initial_metadata,
+                              :metadata_to_send,
+                              :merge_metadata_to_send,
+                              :metadata_sent)
 
     # Operation limits access to an ActiveCall's methods for use as
     # a Operation on the client.
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 75ddff0..d7cd9e6 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -56,7 +56,8 @@
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
     # @param metadata_received [true|false] indicates if metadata has already
     #     been received. Should always be true for server calls
-    def initialize(call, marshal, unmarshal, metadata_received: false)
+    def initialize(call, marshal, unmarshal, metadata_received: false,
+                   req_view: nil)
       fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
       @call = call
       @marshal = marshal
@@ -67,6 +68,7 @@
       @writes_complete = false
       @complete = false
       @done_mutex = Mutex.new
+      @req_view = req_view
     end
 
     # Begins orchestration of the Bidi stream for a client sending requests.
@@ -95,7 +97,15 @@
     #
     # @param gen_each_reply [Proc] generates the BiDi stream replies.
     def run_on_server(gen_each_reply)
-      replys = gen_each_reply.call(read_loop(is_client: false))
+      # Pass in the optional call object parameter if possible
+      if gen_each_reply.arity == 1
+        replys = gen_each_reply.call(read_loop(is_client: false))
+      elsif gen_each_reply.arity == 2
+        replys = gen_each_reply.call(read_loop(is_client: false), @req_view)
+      else
+        fail 'Illegal arity of reply generator'
+      end
+
       write_loop(replys, is_client: false)
     end
 
@@ -141,6 +151,7 @@
         payload = @marshal.call(req)
         # Fails if status already received
         begin
+          @req_view.send_initial_metadata unless @req_view.nil?
           @call.run_batch(SEND_MESSAGE => payload)
         rescue GRPC::Core::CallError => e
           # This is almost definitely caused by a status arriving while still
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 913f55d..584fe78 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -104,7 +104,14 @@
     end
 
     def assert_arity_matches(mth)
-      if request_response? || server_streamer?
+      # A bidi handler function can optionally be passed a second
+      # call object parameter for access to metadata, cancelling, etc.
+      if bidi_streamer?
+        if mth.arity != 2 && mth.arity != 1
+          fail arity_error(mth, 2, "should be #{mth.name}(req, call) or " \
+            "#{mth.name}(req)")
+        end
+      elsif request_response? || server_streamer?
         if mth.arity != 2
           fail arity_error(mth, 2, "should be #{mth.name}(req, call)")
         end
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 7ea2371..8ea798d 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -335,8 +335,11 @@
       return an_rpc if @pool.jobs_waiting <= @max_waiting_requests
       GRPC.logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}")
       noop = proc { |x| x }
+
+      # Create a new active call that knows that metadata hasn't been
+      # sent yet
       c = ActiveCall.new(an_rpc.call, noop, noop, an_rpc.deadline,
-                         metadata_received: true)
+                         metadata_received: true, started: false)
       c.send_status(GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED, '')
       nil
     end
@@ -347,8 +350,11 @@
       return an_rpc if rpc_descs.key?(mth)
       GRPC.logger.warn("UNIMPLEMENTED: #{an_rpc}")
       noop = proc { |x| x }
+
+      # Create a new active call that knows that
+      # metadata hasn't been sent yet
       c = ActiveCall.new(an_rpc.call, noop, noop, an_rpc.deadline,
-                         metadata_received: true)
+                         metadata_received: true, started: false)
       c.send_status(GRPC::Core::StatusCodes::UNIMPLEMENTED, '')
       nil
     end
@@ -396,17 +402,20 @@
       unless @connect_md_proc.nil?
         connect_md = @connect_md_proc.call(an_rpc.method, an_rpc.metadata)
       end
-      an_rpc.call.run_batch(SEND_INITIAL_METADATA => connect_md)
 
       return nil unless available?(an_rpc)
       return nil unless implemented?(an_rpc)
 
-      # Create the ActiveCall
+      # Create the ActiveCall. Indicate that metadata hasnt been sent yet.
       GRPC.logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
       rpc_desc = rpc_descs[an_rpc.method.to_sym]
-      c = ActiveCall.new(an_rpc.call, rpc_desc.marshal_proc,
-                         rpc_desc.unmarshal_proc(:input), an_rpc.deadline,
-                         metadata_received: true)
+      c = ActiveCall.new(an_rpc.call,
+                         rpc_desc.marshal_proc,
+                         rpc_desc.unmarshal_proc(:input),
+                         an_rpc.deadline,
+                         metadata_received: true,
+                         started: false,
+                         metadata_to_send: connect_md)
       mth = an_rpc.method.to_sym
       [c, mth]
     end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 6de1234..6e62af9 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.0.1.pre1'
+  VERSION = '1.1.0.dev'
 end
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index b9af160..1e3ae65 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -111,6 +111,18 @@
 # creates a test stub that accesses host:port securely.
 def create_stub(opts)
   address = "#{opts.host}:#{opts.port}"
+
+  # Provide channel args that request compression by default
+  # for compression interop tests
+  if ['client_compressed_unary',
+      'client_compressed_streaming'].include?(opts.test_case)
+    compression_options =
+      GRPC::Core::CompressionOptions.new(default_algorithm: :gzip)
+    compression_channel_args = compression_options.to_channel_arg_hash
+  else
+    compression_channel_args = {}
+  end
+
   if opts.secure
     creds = ssl_creds(opts.use_test_ca)
     stub_opts = {
@@ -145,10 +157,15 @@
     end
 
     GRPC.logger.info("... connecting securely to #{address}")
+    stub_opts[:channel_args].merge!(compression_channel_args)
     Grpc::Testing::TestService::Stub.new(address, creds, **stub_opts)
   else
     GRPC.logger.info("... connecting insecurely to #{address}")
-    Grpc::Testing::TestService::Stub.new(address, :this_channel_is_insecure)
+    Grpc::Testing::TestService::Stub.new(
+      address,
+      :this_channel_is_insecure,
+      channel_args: compression_channel_args
+    )
   end
 end
 
@@ -216,10 +233,28 @@
   end
 end
 
+# Intended to be used to wrap a call_op, and to adjust
+# the write flag of the call_op in between messages yielded to it.
+class WriteFlagSettingStreamingInputEnumerable
+  attr_accessor :call_op
+
+  def initialize(requests_and_write_flags)
+    @requests_and_write_flags = requests_and_write_flags
+  end
+
+  def each
+    @requests_and_write_flags.each do |request_and_flag|
+      @call_op.write_flag = request_and_flag[:write_flag]
+      yield request_and_flag[:request]
+    end
+  end
+end
+
 # defines methods corresponding to each interop test case.
 class NamedTests
   include Grpc::Testing
   include Grpc::Testing::PayloadType
+  include GRPC::Core::MetadataKeys
 
   def initialize(stub, args)
     @stub = stub
@@ -235,6 +270,48 @@
     perform_large_unary
   end
 
+  def client_compressed_unary
+    # first request used also for the probe
+    req_size, wanted_response_size = 271_828, 314_159
+    expect_compressed = BoolValue.new(value: true)
+    payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
+    req = SimpleRequest.new(response_type: :COMPRESSABLE,
+                            response_size: wanted_response_size,
+                            payload: payload,
+                            expect_compressed: expect_compressed)
+
+    # send a probe to see if CompressedResponse is supported on the server
+    send_probe_for_compressed_request_support do
+      request_uncompressed_args = {
+        COMPRESSION_REQUEST_ALGORITHM => 'identity'
+      }
+      @stub.unary_call(req, metadata: request_uncompressed_args)
+    end
+
+    # make a call with a compressed message
+    resp = @stub.unary_call(req)
+    assert('Expected second unary call with compression to work') do
+      resp.payload.body.length == wanted_response_size
+    end
+
+    # make a call with an uncompressed message
+    stub_options = {
+      COMPRESSION_REQUEST_ALGORITHM => 'identity'
+    }
+
+    req = SimpleRequest.new(
+      response_type: :COMPRESSABLE,
+      response_size: wanted_response_size,
+      payload: payload,
+      expect_compressed: BoolValue.new(value: false)
+    )
+
+    resp = @stub.unary_call(req, metadata: stub_options)
+    assert('Expected second unary call with compression to work') do
+      resp.payload.body.length == wanted_response_size
+    end
+  end
+
   def service_account_creds
     # ignore this test if the oauth options are not set
     if @args.oauth_scope.nil?
@@ -309,6 +386,50 @@
     end
   end
 
+  def client_compressed_streaming
+    # first request used also by the probe
+    first_request = StreamingInputCallRequest.new(
+      payload: Payload.new(type: :COMPRESSABLE, body: nulls(27_182)),
+      expect_compressed: BoolValue.new(value: true)
+    )
+
+    # send a probe to see if CompressedResponse is supported on the server
+    send_probe_for_compressed_request_support do
+      request_uncompressed_args = {
+        COMPRESSION_REQUEST_ALGORITHM => 'identity'
+      }
+      @stub.streaming_input_call([first_request],
+                                 metadata: request_uncompressed_args)
+    end
+
+    second_request = StreamingInputCallRequest.new(
+      payload: Payload.new(type: :COMPRESSABLE, body: nulls(45_904)),
+      expect_compressed: BoolValue.new(value: false)
+    )
+
+    # Create the requests messages and the corresponding write flags
+    # for each message
+    requests = WriteFlagSettingStreamingInputEnumerable.new([
+      { request: first_request,
+        write_flag: 0 },
+      { request: second_request,
+        write_flag: GRPC::Core::WriteFlags::NO_COMPRESS }
+    ])
+
+    # Create the call_op, pass it to the requests enumerable, and
+    # run the call
+    call_op = @stub.streaming_input_call(requests,
+                                         return_op: true)
+    requests.call_op = call_op
+    resp = call_op.execute
+
+    wanted_aggregate_size = 73_086
+
+    assert("#{__callee__}: aggregate payload size is incorrect") do
+      wanted_aggregate_size == resp.aggregated_payload_size
+    end
+  end
+
   def server_streaming
     msg_sizes = [31_415, 9, 2653, 58_979]
     response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
@@ -415,6 +536,29 @@
     end
     resp
   end
+
+  # Send probing message for compressed request on the server, to see
+  # if it's implemented.
+  def send_probe_for_compressed_request_support(&send_probe)
+    bad_status_occured = false
+
+    begin
+      send_probe.call
+    rescue GRPC::BadStatus => e
+      if e.code == GRPC::Core::StatusCodes::INVALID_ARGUMENT
+        bad_status_occured = true
+      else
+        fail AssertionError, "Bad status received but code is #{e.code}"
+      end
+    rescue Exception => e
+      fail AssertionError, "Expected BadStatus. Received: #{e.inspect}"
+    end
+
+    assert('CompressedRequest probe failed') do
+      bad_status_occured
+    end
+  end
+
 end
 
 # Args is used to hold the command line info.
diff --git a/src/ruby/spec/compression_options_spec.rb b/src/ruby/spec/compression_options_spec.rb
new file mode 100644
index 0000000..dbd7e59
--- /dev/null
+++ b/src/ruby/spec/compression_options_spec.rb
@@ -0,0 +1,164 @@
+# 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'
+
+describe GRPC::Core::CompressionOptions do
+  # Note these constants should be updated
+  # according to what the core lib provides.
+
+  # Names of supported compression algorithms
+  ALGORITHMS = [:identity, :deflate, :gzip]
+
+  # Names of valid supported compression levels
+  COMPRESS_LEVELS = [:none, :low, :medium, :high]
+
+  it 'implements to_s' do
+    expect { GRPC::Core::CompressionOptions.new.to_s }.to_not raise_error
+  end
+
+  it '#to_channel_arg_hash gives the same result as #to_hash' do
+    options = GRPC::Core::CompressionOptions.new
+    expect(options.to_channel_arg_hash).to eq(options.to_hash)
+  end
+
+  # Test the normal call sequence of creating an instance
+  # and then obtaining the resulting channel-arg hash that
+  # corresponds to the compression settings of the instance
+  describe 'creating, reading, and converting to channel args hash' do
+    it 'works when no optional args were provided' do
+      options = GRPC::Core::CompressionOptions.new
+
+      ALGORITHMS.each do |algorithm|
+        expect(options.algorithm_enabled?(algorithm)).to be true
+      end
+
+      expect(options.disabled_algorithms).to be_empty
+      expect(options.default_algorithm).to be nil
+      expect(options.default_level).to be nil
+      expect(options.to_hash).to be_instance_of(Hash)
+    end
+
+    it 'works when disabling multiple algorithms' do
+      options = GRPC::Core::CompressionOptions.new(
+        default_algorithm: :identity,
+        default_level: :none,
+        disabled_algorithms: [:gzip, :deflate]
+      )
+
+      [:gzip, :deflate].each do |algorithm|
+        expect(options.algorithm_enabled?(algorithm)).to be false
+        expect(options.disabled_algorithms.include?(algorithm)).to be true
+      end
+
+      expect(options.default_algorithm).to be(:identity)
+      expect(options.default_level).to be(:none)
+      expect(options.to_hash).to be_instance_of(Hash)
+    end
+
+    it 'works when all optional args have been set' do
+      options = GRPC::Core::CompressionOptions.new(
+        default_algorithm: :gzip,
+        default_level: :low,
+        disabled_algorithms: [:deflate]
+      )
+
+      expect(options.algorithm_enabled?(:deflate)).to be false
+      expect(options.algorithm_enabled?(:gzip)).to be true
+      expect(options.disabled_algorithms).to eq([:deflate])
+
+      expect(options.default_algorithm).to be(:gzip)
+      expect(options.default_level).to be(:low)
+      expect(options.to_hash).to be_instance_of(Hash)
+    end
+
+    it 'doesnt fail when no algorithms are disabled' do
+      options = GRPC::Core::CompressionOptions.new(
+        default_algorithm: :identity,
+        default_level: :high
+      )
+
+      ALGORITHMS.each do |algorithm|
+        expect(options.algorithm_enabled?(algorithm)).to be(true)
+      end
+
+      expect(options.disabled_algorithms).to be_empty
+      expect(options.default_algorithm).to be(:identity)
+      expect(options.default_level).to be(:high)
+      expect(options.to_hash).to be_instance_of(Hash)
+    end
+  end
+
+  describe '#new with bad parameters' do
+    it 'should fail with more than one parameter' do
+      blk = proc { GRPC::Core::CompressionOptions.new(:gzip, :none) }
+      expect { blk.call }.to raise_error
+    end
+
+    it 'should fail with a non-hash parameter' do
+      blk = proc { GRPC::Core::CompressionOptions.new(:gzip) }
+      expect { blk.call }.to raise_error
+    end
+  end
+
+  describe '#default_algorithm' do
+    it 'returns nil if unset' do
+      options = GRPC::Core::CompressionOptions.new
+      expect(options.default_algorithm).to be(nil)
+    end
+  end
+
+  describe '#default_level' do
+    it 'returns nil if unset' do
+      options = GRPC::Core::CompressionOptions.new
+      expect(options.default_level).to be(nil)
+    end
+  end
+
+  describe '#disabled_algorithms' do
+    it 'returns an empty list if no algorithms were disabled' do
+      options = GRPC::Core::CompressionOptions.new
+      expect(options.disabled_algorithms).to be_empty
+    end
+  end
+
+  describe '#algorithm_enabled?' do
+    [:none, :any, 'gzip', Object.new, 1].each do |name|
+      it "should fail for parameter ${name} of class #{name.class}" do
+        options = GRPC::Core::CompressionOptions.new(
+          disabled_algorithms: [:gzip])
+
+        blk = proc do
+          options.algorithm_enabled?(name)
+        end
+        expect { blk.call }.to raise_error
+      end
+    end
+  end
+end
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 018580e..48bc61e 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -60,8 +60,10 @@
     end
 
     describe '#multi_req_view' do
-      it 'exposes a fixed subset of the ActiveCall methods' do
-        want = %w(cancelled?, deadline, each_remote_read, metadata, shutdown)
+      it 'exposes a fixed subset of the ActiveCall.methods' do
+        want = %w(cancelled?, deadline, each_remote_read, metadata, \
+                  shutdown, peer, peer_cert, send_initial_metadata, \
+                  initial_metadata_sent)
         v = @client_call.multi_req_view
         want.each do |w|
           expect(v.methods.include?(w))
@@ -70,8 +72,10 @@
     end
 
     describe '#single_req_view' do
-      it 'exposes a fixed subset of the ActiveCall methods' do
-        want = %w(cancelled?, deadline, metadata, shutdown)
+      it 'exposes a fixed subset of the ActiveCall.methods' do
+        want = %w(cancelled?, deadline, metadata, shutdown, \
+                  send_initial_metadata, metadata_to_send, \
+                  merge_metadata_to_send, initial_metadata_sent)
         v = @client_call.single_req_view
         want.each do |w|
           expect(v.methods.include?(w))
@@ -149,6 +153,146 @@
     end
   end
 
+  describe 'sending initial metadata', send_initial_metadata: true do
+    it 'sends metadata before sending a message if it hasnt been sent yet' do
+      call = make_test_call
+      @client_call = ActiveCall.new(
+        call,
+        @pass_through,
+        @pass_through,
+        deadline,
+        started: false)
+
+      metadata = { key: 'dummy_val', other: 'other_val' }
+      expect(@client_call.metadata_sent).to eq(false)
+      @client_call.merge_metadata_to_send(metadata)
+
+      message = 'dummy message'
+
+      expect(call).to(
+        receive(:run_batch)
+          .with(
+            hash_including(
+              CallOps::SEND_INITIAL_METADATA => metadata)).once)
+
+      expect(call).to(
+        receive(:run_batch).with(hash_including(
+                                   CallOps::SEND_MESSAGE => message)).once)
+      @client_call.remote_send(message)
+
+      expect(@client_call.metadata_sent).to eq(true)
+    end
+
+    it 'doesnt send metadata if it thinks its already been sent' do
+      call = make_test_call
+
+      @client_call = ActiveCall.new(call,
+                                    @pass_through,
+                                    @pass_through,
+                                    deadline)
+
+      expect(@client_call.metadata_sent).to eql(true)
+      expect(call).to(
+        receive(:run_batch).with(hash_including(
+                                   CallOps::SEND_INITIAL_METADATA)).never)
+
+      @client_call.remote_send('test message')
+    end
+
+    it 'sends metadata if it is explicitly sent and ok to do so' do
+      call = make_test_call
+
+      @client_call = ActiveCall.new(call,
+                                    @pass_through,
+                                    @pass_through,
+                                    deadline,
+                                    started: false)
+
+      expect(@client_call.metadata_sent).to eql(false)
+
+      metadata = { test_key: 'val' }
+      @client_call.merge_metadata_to_send(metadata)
+      expect(@client_call.metadata_to_send).to eq(metadata)
+
+      expect(call).to(
+        receive(:run_batch).with(hash_including(
+                                   CallOps::SEND_INITIAL_METADATA =>
+                                     metadata)).once)
+      @client_call.send_initial_metadata
+    end
+
+    it 'explicit sending does nothing if metadata has already been sent' do
+      call = make_test_call
+
+      @client_call = ActiveCall.new(call,
+                                    @pass_through,
+                                    @pass_through,
+                                    deadline)
+
+      expect(@client_call.metadata_sent).to eql(true)
+
+      blk = proc do
+        @client_call.send_initial_metadata
+      end
+
+      expect { blk.call }.to_not raise_error
+    end
+  end
+
+  describe '#merge_metadata_to_send', merge_metadata_to_send: true do
+    it 'adds to existing metadata when there is existing metadata to send' do
+      call = make_test_call
+      starting_metadata = {
+        k1: 'key1_val',
+        k2: 'key2_val',
+        k3: 'key3_val'
+      }
+
+      @client_call = ActiveCall.new(
+        call,
+        @pass_through, @pass_through,
+        deadline,
+        started: false,
+        metadata_to_send: starting_metadata)
+
+      expect(@client_call.metadata_to_send).to eq(starting_metadata)
+
+      @client_call.merge_metadata_to_send(
+        k3: 'key3_new_val',
+        k4: 'key4_val')
+
+      expected_md_to_send = {
+        k1: 'key1_val',
+        k2: 'key2_val',
+        k3: 'key3_new_val',
+        k4: 'key4_val' }
+
+      expect(@client_call.metadata_to_send).to eq(expected_md_to_send)
+
+      @client_call.merge_metadata_to_send(k5: 'key5_val')
+      expected_md_to_send.merge!(k5: 'key5_val')
+      expect(@client_call.metadata_to_send).to eq(expected_md_to_send)
+    end
+
+    it 'fails when initial metadata has already been sent' do
+      call = make_test_call
+      @client_call = ActiveCall.new(
+        call,
+        @pass_through,
+        @pass_through,
+        deadline,
+        started: true)
+
+      expect(@client_call.metadata_sent).to eq(true)
+
+      blk = proc do
+        @client_call.merge_metadata_to_send(k1: 'key1_val')
+      end
+
+      expect { blk.call }.to raise_error
+    end
+  end
+
   describe '#client_invoke' do
     it 'sends metadata to the server when present' do
       call = make_test_call
@@ -163,7 +307,26 @@
     end
   end
 
-  describe '#remote_read' do
+  describe '#send_status', send_status: true do
+    it 'works when no metadata or messages have been sent yet' do
+      call = make_test_call
+      ActiveCall.client_invoke(call)
+
+      recvd_rpc = @server.request_call
+      server_call = ActiveCall.new(
+        recvd_rpc.call,
+        @pass_through,
+        @pass_through,
+        deadline,
+        started: false)
+
+      expect(server_call.metadata_sent).to eq(false)
+      blk = proc { server_call.send_status(OK) }
+      expect { blk.call }.to_not raise_error
+    end
+  end
+
+  describe '#remote_read', remote_read: true do
     it 'reads the response sent by a server' do
       call = make_test_call
       ActiveCall.client_invoke(call)
@@ -205,6 +368,31 @@
       expect(client_call.metadata).to eq(expected)
     end
 
+    it 'get a status from server when nothing else sent from server' do
+      client_call = make_test_call
+      ActiveCall.client_invoke(client_call)
+
+      recvd_rpc = @server.request_call
+      recvd_call = recvd_rpc.call
+
+      server_call = ActiveCall.new(
+        recvd_call,
+        @pass_through,
+        @pass_through,
+        deadline,
+        started: false)
+
+      server_call.send_status(OK, 'OK')
+
+      # Check that we can receive initial metadata and a status
+      client_call.run_batch(
+        CallOps::RECV_INITIAL_METADATA => nil)
+      batch_result = client_call.run_batch(
+        CallOps::RECV_STATUS_ON_CLIENT => nil)
+
+      expect(batch_result.status.code).to eq(OK)
+    end
+
     it 'get a nil msg before a status when an OK status is sent' do
       call = make_test_call
       ActiveCall.client_invoke(call)
@@ -329,6 +517,86 @@
     end
   end
 
+  # Test sending of the initial metadata in #run_server_bidi
+  # from the server handler both implicitly and explicitly.
+  describe '#run_server_bidi metadata sending tests', run_server_bidi: true do
+    before(:each) do
+      @requests = ['first message', 'second message']
+      @server_to_client_metadata = { 'test_key' => 'test_val' }
+      @server_status = OK
+
+      @client_call = make_test_call
+      @client_call.run_batch(CallOps::SEND_INITIAL_METADATA => {})
+
+      recvd_rpc = @server.request_call
+      recvd_call = recvd_rpc.call
+      @server_call = ActiveCall.new(
+        recvd_call,
+        @pass_through,
+        @pass_through,
+        deadline,
+        metadata_received: true,
+        started: false,
+        metadata_to_send: @server_to_client_metadata)
+    end
+
+    after(:each) do
+      # Send the requests and send a close so the server can send a status
+      @requests.each do |message|
+        @client_call.run_batch(CallOps::SEND_MESSAGE => message)
+      end
+      @client_call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
+
+      @server_thread.join
+
+      # Expect that initial metadata was sent,
+      # the requests were echoed, and a status was sent
+      batch_result = @client_call.run_batch(
+        CallOps::RECV_INITIAL_METADATA => nil)
+      expect(batch_result.metadata).to eq(@server_to_client_metadata)
+
+      @requests.each do |message|
+        batch_result = @client_call.run_batch(
+          CallOps::RECV_MESSAGE => nil)
+        expect(batch_result.message).to eq(message)
+      end
+
+      batch_result = @client_call.run_batch(
+        CallOps::RECV_STATUS_ON_CLIENT => nil)
+      expect(batch_result.status.code).to eq(@server_status)
+    end
+
+    it 'sends the initial metadata implicitly if not already sent' do
+      # Server handler that doesn't have access to a "call"
+      # It echoes the requests
+      fake_gen_each_reply_with_no_call_param = proc do |msgs|
+        msgs
+      end
+
+      @server_thread = Thread.new do
+        @server_call.run_server_bidi(
+          fake_gen_each_reply_with_no_call_param)
+        @server_call.send_status(@server_status)
+      end
+    end
+
+    it 'sends the metadata when sent explicitly and not already sent' do
+      # Fake server handler that has access to a "call" object and
+      # uses it to explicitly update and send the initial metadata
+      fake_gen_each_reply_with_call_param = proc do |msgs, call_param|
+        call_param.merge_metadata_to_send(@server_to_client_metadata)
+        call_param.send_initial_metadata
+        msgs
+      end
+
+      @server_thread = Thread.new do
+        @server_call.run_server_bidi(
+          fake_gen_each_reply_with_call_param)
+        @server_call.send_status(@server_status)
+      end
+    end
+  end
+
   def expect_server_to_receive(sent_text, **kw)
     c = expect_server_to_be_invoked(**kw)
     expect(c.remote_read).to eq(sent_text)
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index d2080b7..1a89500 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -196,6 +196,9 @@
     def fake_svstream(_arg1, _arg2)
     end
 
+    def fake_three_args(_arg1, _arg2, _arg3)
+    end
+
     it 'raises when a request_response does not have 2 args' do
       [:fake_clstream, :no_arg].each do |mth|
         blk = proc do
@@ -244,8 +247,8 @@
       expect(&blk).to_not raise_error
     end
 
-    it 'raises when a bidi streamer does not have 1 arg' do
-      [:fake_svstream, :no_arg].each do |mth|
+    it 'raises when a bidi streamer does not have 1 or 2 args' do
+      [:fake_three_args, :no_arg].each do |mth|
         blk = proc do
           @bidi_streamer.assert_arity_matches(method(mth))
         end
@@ -259,6 +262,13 @@
       end
       expect(&blk).to_not raise_error
     end
+
+    it 'passes when a bidi streamer has 2 args' do
+      blk = proc do
+        @bidi_streamer.assert_arity_matches(method(:fake_svstream))
+      end
+      expect(&blk).to_not raise_error
+    end
   end
 
   describe '#request_response?' do
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index 205eca0..e457ec0 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -29,6 +29,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.0.1.pre1'
+    VERSION = '1.1.0.dev'
   end
 end
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index 52e8b86..2b6c0b1 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -42,14 +42,16 @@
   <%!
   def get_deps(target_dict):
     deps = []
+    if target_dict.get('baselib', False):
+      deps.append("${_gRPC_BASELIB_LIBRARIES}")
     if target_dict.get('build', None) in ['protoc']:
-      deps.append("libprotoc")
+      deps.append("${_gRPC_PROTOBUF_PROTOC_LIBRARIES}")
     if target_dict.get('secure', False):
-      deps = ["ssl"]
+      deps.append("${_gRPC_SSL_LIBRARIES}")
     if target_dict['name'] in ['grpc++', 'grpc++_unsecure', 'grpc++_codegen_lib']:
-      deps.append("libprotobuf")
+      deps.append("${_gRPC_PROTOBUF_LIBRARIES}")
     elif target_dict['name'] in ['grpc']:
-      deps.append("zlibstatic")
+      deps.append("${_gRPC_ZLIB_LIBRARIES}")
     for d in target_dict.get('deps', []):
       deps.append(d)
     return deps
@@ -64,39 +66,138 @@
   set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
   project(<%text>${PACKAGE_NAME}</%text> C CXX)
 
-  if(NOT BORINGSSL_ROOT_DIR)
-    set(BORINGSSL_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/boringssl)
-  endif()
-  if(NOT PROTOBUF_ROOT_DIR)
-    set(PROTOBUF_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/protobuf)
-  endif()
-  if(NOT ZLIB_ROOT_DIR)
-    set(ZLIB_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/zlib)
+  if (NOT MSVC)
+    set(gRPC_INSTALL ON CACHE BOOL "Generate installation target")
+  else()
+    set(gRPC_INSTALL OFF CACHE BOOL "Generate installation target")
   endif()
 
-  # Building the protobuf tests require gmock what is not part of a standard protobuf checkout.
-  # Disable them unless they are explicitly requested from the cmake command line (when we assume
-  # gmock is downloaded to the right location inside protobuf).
-  if(NOT protobuf_BUILD_TESTS)
-    set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests")
+  set(gRPC_ZLIB_PROVIDER "module" CACHE STRING "Provider of zlib library")
+  set_property(CACHE gRPC_ZLIB_PROVIDER PROPERTY STRINGS "module" "package")
+
+  set(gRPC_SSL_PROVIDER "module" CACHE STRING "Provider of ssl library")
+  set_property(CACHE gRPC_SSL_PROVIDER PROPERTY STRINGS "module" "package")
+
+  set(gRPC_PROTOBUF_PROVIDER "module" CACHE STRING "Provider of protobuf library")
+  set_property(CACHE gRPC_PROTOBUF_PROVIDER PROPERTY STRINGS "module" "package")
+
+  set(gRPC_USE_PROTO_LITE OFF CACHE BOOL "Use the protobuf-lite library")
+
+  if (MSVC)
+    add_definitions( -D_WIN32_WINNT=0x600 )
   endif()
 
-  add_subdirectory(<%text>${BORINGSSL_ROOT_DIR}</%text> third_party/boringssl)
-  add_subdirectory(<%text>${PROTOBUF_ROOT_DIR}</%text>/cmake third_party/protobuf)
-  add_subdirectory(<%text>${ZLIB_ROOT_DIR}</%text> third_party/zlib)
+  if (gRPC_USE_PROTO_LITE)
+    set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf-lite")
+    add_definitions("-DGRPC_USE_PROTO_LITE")
+  else()
+    set(_gRPC_PROTOBUF_LIBRARY_NAME "libprotobuf")
+  endif()
 
-  set(CMAKE_C_FLAGS   "<%text>${CMAKE_C_FLAGS}</%text>   -std=c11")
-  set(CMAKE_CXX_FLAGS "<%text>${CMAKE_CXX_FLAGS}</%text> -std=c++11")
+  if("<%text>${gRPC_ZLIB_PROVIDER}</%text>" STREQUAL "module")
+    if(NOT ZLIB_ROOT_DIR)
+      set(ZLIB_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/zlib)
+    endif()
+    set(ZLIB_INCLUDE_DIR "<%text>${ZLIB_ROOT_DIR}</%text>")
+    if(EXISTS "<%text>${ZLIB_ROOT_DIR}</%text>/CMakeLists.txt")
+        add_subdirectory(<%text>${ZLIB_ROOT_DIR}</%text> third_party/zlib)
+        if(TARGET zlibstatic)
+            set(_gRPC_ZLIB_LIBRARIES zlibstatic)
+        endif()
+    else()
+        message(WARNING "gRPC_ZLIB_PROVIDER is \"module\" but ZLIB_ROOT_DIR is wrong")
+    endif()
+  elseif("<%text>${gRPC_ZLIB_PROVIDER}</%text>" STREQUAL "package")
+    find_package(ZLIB)
+    if(TARGET ZLIB::ZLIB)
+      set(_gRPC_ZLIB_LIBRARIES ZLIB::ZLIB)
+    endif()
+    set(_gRPC_FIND_ZLIB "if(NOT ZLIB_FOUND)\n  find_package(ZLIB)\nendif()")
+  endif()
+
+  if("<%text>${gRPC_PROTOBUF_PROVIDER}</%text>" STREQUAL "module")
+    # Building the protobuf tests require gmock what is not part of a standard protobuf checkout.
+    # Disable them unless they are explicitly requested from the cmake command line (when we assume
+    # gmock is downloaded to the right location inside protobuf).
+    if(NOT protobuf_BUILD_TESTS)
+      set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests")
+    endif()
+    if(NOT PROTOBUF_ROOT_DIR)
+      set(PROTOBUF_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/protobuf)
+    endif()
+    if(EXISTS "<%text>${PROTOBUF_ROOT_DIR}</%text>/cmake/CMakeLists.txt")
+      set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "Link static runtime libraries")
+      add_subdirectory(<%text>${PROTOBUF_ROOT_DIR}</%text>/cmake third_party/protobuf)
+      if(TARGET <%text>${_gRPC_PROTOBUF_LIBRARY_NAME}</%text>)
+        set(_gRPC_PROTOBUF_LIBRARIES <%text>${_gRPC_PROTOBUF_LIBRARY_NAME}</%text>)
+      endif()
+      if(TARGET libprotoc)
+        set(_gRPC_PROTOBUF_PROTOC_LIBRARIES libprotoc)
+      endif()
+    else()
+        message(WARNING "gRPC_PROTOBUF_PROVIDER is \"module\" but PROTOBUF_ROOT_DIR is wrong")
+    endif()
+  elseif("<%text>${gRPC_PROTOBUF_PROVIDER}</%text>" STREQUAL "package")
+    find_package(protobuf CONFIG)
+    if(protobuf_FOUND)
+      if(TARGET protobuf::<%text>${_gRPC_PROTOBUF_LIBRARY_NAME}</%text>)
+        set(_gRPC_PROTOBUF_LIBRARIES protobuf::<%text>${_gRPC_PROTOBUF_LIBRARY_NAME}</%text>)
+      endif()
+      if(TARGET protobuf::libprotoc)
+        set(_gRPC_PROTOBUF_PROTOC_LIBRARIES protobuf::libprotoc)
+      endif()
+      set(_gRPC_FIND_PROTOBUF "if(NOT protobuf_FOUND)\n  find_package(protobuf CONFIG)\nendif()")
+    else()
+      find_package(Protobuf MODULE)
+      set(_gRPC_FIND_PROTOBUF "if(NOT Protobuf_FOUND)\n  find_package(Protobuf)\nendif()")
+    endif()
+  endif()
+
+  if("<%text>${gRPC_SSL_PROVIDER}</%text>" STREQUAL "module")
+    if(NOT BORINGSSL_ROOT_DIR)
+      set(BORINGSSL_ROOT_DIR <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/boringssl)
+    endif()
+    if(EXISTS "<%text>${BORINGSSL_ROOT_DIR}</%text>/CMakeLists.txt")
+      add_subdirectory(<%text>${BORINGSSL_ROOT_DIR}</%text> third_party/boringssl)
+      if(TARGET ssl)
+        set(_gRPC_SSL_LIBRARIES ssl)
+      endif()
+    else()
+        message(WARNING "gRPC_SSL_PROVIDER is \"module\" but BORINGSSL_ROOT_DIR is wrong")
+    endif()
+  elseif("<%text>${gRPC_SSL_PROVIDER}</%text>" STREQUAL "package")
+    find_package(OpenSSL)
+    if(TARGET OpenSSL::SSL)
+      set(_gRPC_SSL_LIBRARIES OpenSSL::SSL)
+    endif()
+    set(_gRPC_FIND_SSL "if(NOT OpenSSL_FOUND)\n  find_package(OpenSSL)\nendif()")
+  endif()
+
+  if(NOT MSVC)
+    set(CMAKE_C_FLAGS   "<%text>${CMAKE_C_FLAGS}</%text>   -std=c11")
+    set(CMAKE_CXX_FLAGS "<%text>${CMAKE_CXX_FLAGS}</%text> -std=c++11")
+  endif()
+
+  if(WIN32 AND MSVC)
+    set(_gRPC_BASELIB_LIBRARIES wsock32 ws2_32)
+  endif()
+
+  include(GNUInstallDirs)
+  if(NOT DEFINED CMAKE_INSTALL_CMAKEDIR)
+    set(CMAKE_INSTALL_CMAKEDIR "<%text>${CMAKE_INSTALL_LIBDIR}</%text>/cmake/gRPC")
+  endif()
 
   % for lib in libs:
   % if lib.build in ["all", "protoc", "tool"]:
     ${cc_library(lib)}
+    ${cc_install(lib)}
   % endif
   % endfor
 
   % for tgt in targets:
   % if tgt.build in ["all", "protoc", "tool"]:
   ${cc_binary(tgt)}
+  ${cc_install(tgt)}
   % endif
   % endfor
 
@@ -112,7 +213,7 @@
     PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/include
     PRIVATE <%text>${BORINGSSL_ROOT_DIR}</%text>/include
     PRIVATE <%text>${PROTOBUF_ROOT_DIR}</%text>/src
-    PRIVATE <%text>${ZLIB_ROOT_DIR}</%text>
+    PRIVATE <%text>${ZLIB_INCLUDE_DIR}</%text>
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/zlib
   )
 
@@ -123,6 +224,20 @@
   % endfor
   )
   % endif
+
+  % if len(lib.get('public_headers', [])) > 0:
+  foreach(_hdr
+  % for hdr in lib.get('public_headers', []):
+    ${hdr}
+  % endfor
+  )
+    string(REPLACE "include/" "" _path <%text>${_hdr}</%text>)
+    get_filename_component(_path <%text>${_path}</%text> PATH)
+    install(FILES <%text>${_hdr}</%text>
+      DESTINATION "<%text>${CMAKE_INSTALL_INCLUDEDIR}/${_path}</%text>"
+    )
+  endforeach()
+  % endif
   </%def>
 
   <%def name="cc_binary(tgt)">
@@ -150,3 +265,27 @@
   % endif
   </%def>
 
+  <%def name="cc_install(tgt)">
+  if (gRPC_INSTALL)
+    install(TARGETS ${tgt.name} EXPORT gRPCTargets
+      RUNTIME DESTINATION <%text>${CMAKE_INSTALL_BINDIR}</%text>
+      LIBRARY DESTINATION <%text>${CMAKE_INSTALL_LIBDIR}</%text>
+      ARCHIVE DESTINATION <%text>${CMAKE_INSTALL_LIBDIR}</%text>
+    )
+  endif()
+  </%def>
+
+  if (gRPC_INSTALL)
+    install(EXPORT gRPCTargets
+      DESTINATION <%text>${CMAKE_INSTALL_CMAKEDIR}</%text>
+      NAMESPACE gRPC::
+    )
+  endif()
+
+  foreach(_config gRPCConfig gRPCConfigVersion)
+    configure_file(tools/cmake/<%text>${_config}</%text>.cmake.in
+      <%text>${_config}</%text>.cmake @ONLY)
+    install(FILES <%text>${CMAKE_CURRENT_BINARY_DIR}/${_config}</%text>.cmake
+      DESTINATION <%text>${CMAKE_INSTALL_CMAKEDIR}</%text>
+    )
+  endforeach()
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 3c03f91..e6a28d1 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -282,6 +282,29 @@
   LDFLAGS += -pthread
   endif
 
+  #
+  # The steps for cross-compiling are as follows:
+  # First, clone and make install of grpc using the native compilers for the host.
+  # Also, install protoc (e.g., from a package like apt-get)
+  # Then clone a fresh grpc for the actual cross-compiled build
+  # Set the environment variable GRPC_CROSS_COMPILE to true
+  # Set CC, CXX, LD, LDXX, AR, and STRIP to the cross-compiling binaries
+  # Also set PROTOBUF_CONFIG_OPTS to indicate cross-compilation to protobuf (e.g.,
+  #  PROTOBUF_CONFIG_OPTS="--host=arm-linux --with-protoc=/usr/local/bin/protoc" )
+  # Set HAS_PKG_CONFIG=false
+  # To build tests, go to third_party/gflags and follow its ccmake instructions
+  # Make sure that you enable building shared libraries and set your prefix to
+  # something useful like /usr/local/cross
+  # You will also need to set GRPC_CROSS_LDOPTS and GRPC_CROSS_AROPTS to hold
+  # additional required arguments for LD and AR (examples below)
+  # Then you can do a make from the cross-compiling fresh clone!
+  #
+  ifeq ($(GRPC_CROSS_COMPILE),true)
+  LDFLAGS += $(GRPC_CROSS_LDOPTS) # e.g. -L/usr/local/lib -L/usr/local/cross/lib
+  AROPTS = $(GRPC_CROSS_AROPTS) # e.g., rc --target=elf32-little
+  USE_BUILT_PROTOC = false
+  endif
+
   GTEST_LIB = -Ithird_party/googletest/include -Ithird_party/googletest third_party/googletest/src/gtest-all.cc
   GTEST_LIB += -lgflags
   ifeq ($(V),1)
@@ -597,6 +620,15 @@
 
   CPPFLAGS := -Ithird_party/googletest/include $(CPPFLAGS)
 
+  PROTOC_PLUGINS_ALL =\
+  % for tgt in targets:
+  % if tgt.build == 'protoc':
+   $(BINDIR)/$(CONFIG)/${tgt.name}\
+  % endif
+  % endfor
+
+  PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG)
+
   ifeq ($(HAS_SYSTEM_PROTOBUF),true)
   ifeq ($(HAS_PKG_CONFIG),true)
   PROTOBUF_PKG_CONFIG = true
@@ -611,12 +643,19 @@
   else
   PC_LIBS_GRPCXX = -lprotobuf
   endif
+  PROTOC_PLUGINS = $(PROTOC_PLUGINS_ALL)
   else
   ifeq ($(HAS_EMBEDDED_PROTOBUF),true)
   PROTOBUF_DEP = $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a
   CPPFLAGS := -Ithird_party/protobuf/src $(CPPFLAGS)
   LDFLAGS := -L$(LIBDIR)/$(CONFIG)/protobuf $(LDFLAGS)
+  ifneq ($(USE_BUILT_PROTOC),false)
   PROTOC = $(BINDIR)/$(CONFIG)/protobuf/protoc
+  PROTOC_PLUGINS = $(PROTOC_PLUGINS_ALL)
+  else
+  PROTOC_PLUGINS =
+  PROTOC_PLUGINS_DIR = $(prefix)/bin
+  endif
   else
   NO_PROTOBUF = true
   endif
@@ -657,13 +696,6 @@
 
   .SECONDARY = %.pb.h %.pb.cc
 
-  PROTOC_PLUGINS =\
-  % for tgt in targets:
-  % if tgt.build == 'protoc':
-   $(BINDIR)/$(CONFIG)/${tgt.name}\
-  % endif
-  % endfor
-
   ifeq ($(DEP_MISSING),)
   all: static shared plugins\
   % for tgt in targets:
@@ -785,7 +817,7 @@
 
   $(LIBDIR)/$(CONFIG)/protobuf/libprotobuf.a: third_party/protobuf/configure
   	$(E) "[MAKE]    Building protobuf"
-  	$(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g $(PROTOBUF_LDFLAGS_EXTRA)" CPPFLAGS="$(PIC_CPPFLAGS) $(CPPFLAGS_$(CONFIG)) -g $(PROTOBUF_CPPFLAGS_EXTRA)" ./configure --disable-shared --enable-static)
+  	$(Q)(cd third_party/protobuf ; CC="$(CC)" CXX="$(CXX)" LDFLAGS="$(LDFLAGS_$(CONFIG)) -g $(PROTOBUF_LDFLAGS_EXTRA)" CPPFLAGS="$(PIC_CPPFLAGS) $(CPPFLAGS_$(CONFIG)) -g $(PROTOBUF_CPPFLAGS_EXTRA)" ./configure --disable-shared --enable-static $(PROTOBUF_CONFIG_OPTS))
   	$(Q)$(MAKE) -C third_party/protobuf clean
   	$(Q)$(MAKE) -C third_party/protobuf
   	$(Q)mkdir -p $(LIBDIR)/$(CONFIG)/protobuf
@@ -1117,7 +1149,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=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $<
+  	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin $<
   endif
 
   % endfor
@@ -1387,7 +1419,7 @@
   	$(E) "[AR]      Creating $@"
   	$(Q) mkdir -p `dirname $@`
   	$(Q) rm -f $(LIBDIR)/$(CONFIG)/lib${lib.name}.a
-  	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(LIB${lib.name.upper()}_OBJS) \
+  	$(Q) $(AR) $(AROPTS) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(LIB${lib.name.upper()}_OBJS) \
   % if lib.get('baselib', False):
    $(LIBGPR_OBJS) \
    $(ZLIB_MERGE_OBJS) \
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index 7d735d3..1d5a473 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -128,6 +128,8 @@
       'ALWAYS_SEARCH_USER_PATHS' => 'NO',
     }
 
+    s.default_subspecs = 'Interface', 'Implementation'
+
     # Like many other C libraries, gRPC-Core has its public headers under `include/<libname>/` and its
     # sources and private headers in other directories outside `include/`. Cocoapods' linter doesn't
     # allow any header to be listed outside the `header_mappings_dir` (even though doing so works in
@@ -154,4 +156,30 @@
 
       ss.private_header_files = ${ruby_multiline_list(grpc_private_headers(libs), 30)}
     end
+
+    s.subspec 'Cronet-Interface' do |ss|
+      ss.header_mappings_dir = 'include/grpc'
+      ss.source_files = 'include/grpc/grpc_cronet.h'
+    end
+
+    s.subspec 'Cronet-Implementation' do |ss|
+      ss.header_mappings_dir = '.'
+      ss.source_files = 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c',
+                        'src/core/ext/transport/cronet/transport/cronet_transport.c'
+    end
+
+    s.subspec 'Tests' do |ss|
+      ss.header_mappings_dir = '.'
+
+      ss.source_files = 'test/core/end2end/cq_verifier.{c,h}',
+                        'test/core/end2end/end2end_tests.{c,h}',
+                        'test/core/end2end/tests/*.{c,h}',
+                        'test/core/end2end/data/*.{c,h}',
+                        'test/core/util/test_config.{c,h}',
+                        'test/core/util/port.h',
+                        'test/core/util/port_posix.c',
+                        'test/core/util/port_server_client.{c,h}'
+
+      ss.dependency 'CronetFramework'
+    end
   end
diff --git a/templates/tools/dockerfile/apt_get_pyenv.include b/templates/tools/dockerfile/apt_get_pyenv.include
new file mode 100644
index 0000000..70e9028
--- /dev/null
+++ b/templates/tools/dockerfile/apt_get_pyenv.include
@@ -0,0 +1,18 @@
+# Install dependencies for pyenv
+RUN apt-get update && apt-get install -y ${'\\'}
+  libbz2-dev ${'\\'}
+  libncurses5-dev ${'\\'}
+  libncursesw5-dev ${'\\'}
+  libreadline-dev ${'\\'}
+  libsqlite3-dev ${'\\'}
+  libssl-dev ${'\\'}
+  llvm ${'\\'}
+  mercurial ${'\\'}
+  zlib1g-dev && apt-get clean
+
+# Install Pyenv and dev Python versions 3.5 and 3.6
+RUN curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
+RUN pyenv update
+RUN pyenv install 3.5-dev
+RUN pyenv install 3.6-dev
+RUN pyenv local 3.5-dev 3.6-dev
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
index 4cb8d3b..da0c70a 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../csharp_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
index e39175a..aba0a04 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
index 542c81d..38a5ca7 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM golang:1.5
   
   <%include file="../../go_path.include"/>
+  <%include file="../../python_deps.include"/>
   # Define the default command.
   CMD ["bash"]
   
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
index 542c81d..38a5ca7 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM golang:1.5
   
   <%include file="../../go_path.include"/>
+  <%include file="../../python_deps.include"/>
   # Define the default command.
   CMD ["bash"]
   
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
index c286e80..3d5e7ee 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
@@ -32,7 +32,8 @@
   FROM debian:jessie
   
   <%include file="../../java_deps.include"/>
-  
+  <%include file="../../python_deps.include"/>
+
   # Trigger download of as many Gradle artifacts as possible.
   RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && ${'\\'}
     cd grpc-java && ${'\\'}
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
index 89bb9ac..01a0307 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../node_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
index c3625b9..fbd8242 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ruby_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
diff --git a/templates/tools/dockerfile/python_deps.include b/templates/tools/dockerfile/python_deps.include
index 3162364..26c91f4 100644
--- a/templates/tools/dockerfile/python_deps.include
+++ b/templates/tools/dockerfile/python_deps.include
@@ -11,4 +11,4 @@
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template
index 0741782..5d805bb 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ccache_setup.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../gcp_api_libraries.include"/>
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile.template
index ac087c5..18f06b7 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ccache_setup.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../gcp_api_libraries.include"/>
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile.template
index 3ed3d65..e02254c 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM golang:1.5
   
   <%include file="../../gcp_api_libraries.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../go_path.include"/>
   # Define the default command.
   CMD ["bash"]
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile.template
index 17ed99f..2bb2f9b 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ccache_setup.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../gcp_api_libraries.include"/>
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile.template
index c50d38d..d70b751 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../node_deps.include"/>
   <%include file="../../gcp_api_libraries.include"/>
   <%include file="../../run_tests_addons.include"/>
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template
index df61808..13a250e 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ruby_deps.include"/>
   <%include file="../../gcp_api_libraries.include"/>
   <%include file="../../php_deps.include"/>
diff --git a/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template b/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template
index 8b933aa..1819977 100644
--- a/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template
+++ b/templates/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ccache_setup.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../gcp_api_libraries.include"/>
diff --git a/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
index e9cab57..24dad48 100644
--- a/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../csharp_deps.include"/>
   
   # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
diff --git a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
index 4cb8d3b..da0c70a 100644
--- a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../csharp_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
index 04abf9f..0476724 100644
--- a/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../clang_update.include"/>
   <%include file="../../run_tests_addons.include"/>
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
index 7f43e75..49fbea0 100644
--- a/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
@@ -32,8 +32,8 @@
   FROM 32bit/debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
-  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
index 4950a82..8a95cad 100644
--- a/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM ubuntu:14.04
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../run_tests_addons_nocache.include"/>
   # Define the default command.
diff --git a/templates/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile.template
index e395379..42ad6c1 100644
--- a/templates/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM ubuntu:16.04
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   
@@ -42,4 +43,3 @@
   
   # Define the default command.
   CMD ["bash"]
-  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template
index e77b3d9..b6a3b0d 100644
--- a/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:wheezy
 
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
 
   RUN apt-get update && apt-get install -y ${'\\'}
diff --git a/templates/tools/dockerfile/test/fuzzer/Dockerfile.template b/templates/tools/dockerfile/test/fuzzer/Dockerfile.template
index 33df275..6d7cb72 100644
--- a/templates/tools/dockerfile/test/fuzzer/Dockerfile.template
+++ b/templates/tools/dockerfile/test/fuzzer/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM debian:jessie
 
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../cxx_deps.include"/>
   <%include file="../../clang_update.include"/>
   <%include file="../../run_tests_addons.include"/>
diff --git a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
index 5a62333..72b098f 100644
--- a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
@@ -32,8 +32,8 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../node_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
-  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
index fffac89..0cfa373 100644
--- a/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
@@ -32,8 +32,8 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../php_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
-  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/python_pyenv_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_pyenv_x64/Dockerfile.template
new file mode 100644
index 0000000..f9a4dcb
--- /dev/null
+++ b/templates/tools/dockerfile/test/python_pyenv_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # 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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
+  <%include file="../../apt_get_pyenv.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
diff --git a/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
index 70baddf..35838bc 100644
--- a/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
@@ -32,8 +32,8 @@
   FROM debian:jessie
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   <%include file="../../ruby_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
-  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
index 9987e35..12309b6 100644
--- a/templates/tools/dockerfile/test/sanity/Dockerfile.template
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -32,6 +32,7 @@
   FROM ubuntu:15.10
   
   <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
   #========================
   # Sanity test dependencies
   RUN apt-get update && apt-get install -y ${"\\"}
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 24ee338..be88d4a 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -130,7 +130,7 @@
   grpc_server_start(a.server);
   transport = grpc_create_chttp2_transport(&exec_ctx, NULL, sfd.server, 0);
   server_setup_transport(&a, transport);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 
   /* Bind everything into the same pollset */
diff --git a/test/core/census/README b/test/core/census/README
new file mode 100644
index 0000000..d5363b7
--- /dev/null
+++ b/test/core/census/README
@@ -0,0 +1,7 @@
+Test source and data files for Census.
+
+binary proto files (*.pb) in data directory are generated from the *.txt file,
+via:
+
+BASE="filename"
+cat $BASE.txt | protoc --encode=google.census.Resource census.proto > $BASE.pb
diff --git a/test/core/census/data/resource_empty_name.pb b/test/core/census/data/resource_empty_name.pb
new file mode 100644
index 0000000..4d54744
--- /dev/null
+++ b/test/core/census/data/resource_empty_name.pb
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/test/core/census/data/resource_empty_name.txt b/test/core/census/data/resource_empty_name.txt
new file mode 100644
index 0000000..271fd32
--- /dev/null
+++ b/test/core/census/data/resource_empty_name.txt
@@ -0,0 +1,5 @@
+# Name is present, but empty.
+name : ''
+unit {
+  numerator : SECS
+}
diff --git a/test/core/census/data/resource_full.pb b/test/core/census/data/resource_full.pb
new file mode 100644
index 0000000..e4c6a2a
--- /dev/null
+++ b/test/core/census/data/resource_full.pb
Binary files differ
diff --git a/test/core/census/data/resource_full.txt b/test/core/census/data/resource_full.txt
new file mode 100644
index 0000000..1aa2faf
--- /dev/null
+++ b/test/core/census/data/resource_full.txt
@@ -0,0 +1,9 @@
+# A full resource definition - all fields filled out.
+name : 'full_resource'
+description : 'A resource with everything defined'
+unit {
+  # Megabits per second.
+  prefix : 6
+  numerator : BITS
+  denominator : SECS
+}
diff --git a/test/core/census/data/resource_minimal_good.pb b/test/core/census/data/resource_minimal_good.pb
new file mode 100644
index 0000000..7100c46
--- /dev/null
+++ b/test/core/census/data/resource_minimal_good.pb
@@ -0,0 +1,2 @@
+
+minimal_good
\ No newline at end of file
diff --git a/test/core/census/data/resource_minimal_good.txt b/test/core/census/data/resource_minimal_good.txt
new file mode 100644
index 0000000..a7a7e71
--- /dev/null
+++ b/test/core/census/data/resource_minimal_good.txt
@@ -0,0 +1,5 @@
+# A minimal "good" Resource definition: has a name and numerator/unit.
+name : 'minimal_good'
+unit {
+  numerator : SECS
+}
diff --git a/test/core/census/data/resource_no_name.pb b/test/core/census/data/resource_no_name.pb
new file mode 100644
index 0000000..4d54744
--- /dev/null
+++ b/test/core/census/data/resource_no_name.pb
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/test/core/census/data/resource_no_name.txt b/test/core/census/data/resource_no_name.txt
new file mode 100644
index 0000000..8f12a91
--- /dev/null
+++ b/test/core/census/data/resource_no_name.txt
@@ -0,0 +1,4 @@
+# The minimal good Resource without a name.
+unit {
+  numerator : SECS
+}
diff --git a/test/core/census/data/resource_no_numerator.pb b/test/core/census/data/resource_no_numerator.pb
new file mode 100644
index 0000000..2a5ccee
--- /dev/null
+++ b/test/core/census/data/resource_no_numerator.pb
@@ -0,0 +1,2 @@
+
+resource_no_numeratorýÿÿÿÿÿÿÿÿ
\ No newline at end of file
diff --git a/test/core/census/data/resource_no_numerator.txt b/test/core/census/data/resource_no_numerator.txt
new file mode 100644
index 0000000..fc1fec7
--- /dev/null
+++ b/test/core/census/data/resource_no_numerator.txt
@@ -0,0 +1,6 @@
+# Resource without a numerator
+name : 'resource_no_numerator'
+unit {
+  prefix : -3
+  denominator : SECS
+}
diff --git a/test/core/census/data/resource_no_unit.pb b/test/core/census/data/resource_no_unit.pb
new file mode 100644
index 0000000..9dca262
--- /dev/null
+++ b/test/core/census/data/resource_no_unit.pb
@@ -0,0 +1,2 @@
+
+resource_no_unit
\ No newline at end of file
diff --git a/test/core/census/data/resource_no_unit.txt b/test/core/census/data/resource_no_unit.txt
new file mode 100644
index 0000000..c5d5115
--- /dev/null
+++ b/test/core/census/data/resource_no_unit.txt
@@ -0,0 +1,2 @@
+# The minimal good resource without a unit
+name : 'resource_no_unit'
diff --git a/test/core/census/resource_test.c b/test/core/census/resource_test.c
new file mode 100644
index 0000000..f0e7039
--- /dev/null
+++ b/test/core/census/resource_test.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * 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/ext/census/resource.h"
+#include <grpc/census.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "src/core/ext/census/base_resources.h"
+#include "test/core/util/test_config.h"
+
+// Test all the functionality for dealing with Resources.
+
+// Just startup and shutdown resources subsystem.
+static void test_enable_disable() {
+  initialize_resources();
+  shutdown_resources();
+}
+
+// A blank/empty initialization should not work.
+static void test_empty_definition() {
+  initialize_resources();
+  int32_t rid = census_define_resource(NULL, 0);
+  GPR_ASSERT(rid == -1);
+  uint8_t buffer[50] = {0};
+  rid = census_define_resource(buffer, 50);
+  GPR_ASSERT(rid == -1);
+  shutdown_resources();
+}
+
+// Given a file name, read raw proto and define the resource included within.
+// Returns resource id from census_define_resource().
+static int32_t define_resource_from_file(const char *file) {
+#define BUF_SIZE 512
+  uint8_t buffer[BUF_SIZE];
+  FILE *input = fopen(file, "rb");
+  GPR_ASSERT(input != NULL);
+  size_t nbytes = fread(buffer, 1, BUF_SIZE, input);
+  GPR_ASSERT(nbytes != 0 && nbytes < BUF_SIZE && feof(input) && !ferror(input));
+  int32_t rid = census_define_resource(buffer, nbytes);
+  GPR_ASSERT(fclose(input) == 0);
+  return rid;
+}
+
+// Test definition of a single resource, using a proto read from a file. The
+// `succeed` parameter indicates whether we expect the definition to succeed or
+// fail. `name` is used to check that the returned resource can be looked up by
+// name.
+static void test_define_single_resource(const char *file, const char *name,
+                                        bool succeed) {
+  gpr_log(GPR_INFO, "Test defining resource \"%s\"\n", name);
+  initialize_resources();
+  int32_t rid = define_resource_from_file(file);
+  if (succeed) {
+    GPR_ASSERT(rid >= 0);
+    int32_t rid2 = census_resource_id(name);
+    GPR_ASSERT(rid == rid2);
+  } else {
+    GPR_ASSERT(rid < 0);
+  }
+  shutdown_resources();
+}
+
+// Try deleting various resources (both those that exist and those that don't).
+static void test_delete_resource(const char *minimal_good, const char *full) {
+  initialize_resources();
+  // Try deleting resource before any are defined.
+  census_delete_resource(0);
+  // Create and check a couple of resources.
+  int32_t rid1 = define_resource_from_file(minimal_good);
+  int32_t rid2 = define_resource_from_file(full);
+  GPR_ASSERT(rid1 >= 0 && rid2 >= 0 && rid1 != rid2);
+  int32_t rid3 = census_resource_id("minimal_good");
+  int32_t rid4 = census_resource_id("full_resource");
+  GPR_ASSERT(rid1 == rid3 && rid2 == rid4);
+  // Try deleting non-existant resources.
+  census_delete_resource(-1);
+  census_delete_resource(rid1 + rid2 + 1);
+  census_delete_resource(10000000);
+  // Delete one of the previously defined resources and check for deletion.
+  census_delete_resource(rid1);
+  rid3 = census_resource_id("minimal_good");
+  GPR_ASSERT(rid3 < 0);
+  // Check that re-adding works.
+  rid1 = define_resource_from_file(minimal_good);
+  GPR_ASSERT(rid1 >= 0);
+  rid3 = census_resource_id("minimal_good");
+  GPR_ASSERT(rid1 == rid3);
+  shutdown_resources();
+}
+
+// Test define base resources.
+static void test_base_resources() {
+  initialize_resources();
+  define_base_resources();
+  int32_t rid1 = census_resource_id("client_rpc_latency");
+  int32_t rid2 = census_resource_id("server_rpc_latency");
+  GPR_ASSERT(rid1 >= 0 && rid2 >= 0 && rid1 != rid2);
+  shutdown_resources();
+}
+
+int main(int argc, char **argv) {
+  const char *resource_empty_name_pb, *resource_full_pb,
+      *resource_minimal_good_pb, *resource_no_name_pb,
+      *resource_no_numerator_pb, *resource_no_unit_pb;
+  if (argc == 7) {
+    resource_empty_name_pb = argv[1];
+    resource_full_pb = argv[2];
+    resource_minimal_good_pb = argv[3];
+    resource_no_name_pb = argv[4];
+    resource_no_numerator_pb = argv[5];
+    resource_no_unit_pb = argv[6];
+  } else {
+    GPR_ASSERT(argc == 1);
+    resource_empty_name_pb = "test/core/census/data/resource_empty_name.pb";
+    resource_full_pb = "test/core/census/data/resource_full.pb";
+    resource_minimal_good_pb = "test/core/census/data/resource_minimal_good.pb";
+    resource_no_name_pb = "test/core/census/data/resource_no_name.pb";
+    resource_no_numerator_pb = "test/core/census/data/resource_no_numerator.pb";
+    resource_no_unit_pb = "test/core/census/data/resource_no_unit.pb";
+  }
+  grpc_test_init(argc, argv);
+  test_enable_disable();
+  test_empty_definition();
+  test_define_single_resource(resource_minimal_good_pb, "minimal_good", true);
+  test_define_single_resource(resource_full_pb, "full_resource", true);
+  test_define_single_resource(resource_no_name_pb, "resource_no_name", false);
+  test_define_single_resource(resource_no_numerator_pb, "resource_no_numerator",
+                              false);
+  test_define_single_resource(resource_no_unit_pb, "resource_no_unit", false);
+  test_define_single_resource(resource_empty_name_pb, "resource_empty_name",
+                              false);
+  test_delete_resource(resource_minimal_good_pb, resource_full_pb);
+  test_base_resources();
+  return 0;
+}
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index f9561be..569b3f7 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -53,17 +53,20 @@
   *(int *)(elem->channel_data) = 0;
 }
 
-static void call_init_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {
+static grpc_error *call_init_func(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
   ++*(int *)(elem->channel_data);
   *(int *)(elem->call_data) = 0;
+  return GRPC_ERROR_NONE;
 }
 
 static void channel_destroy_func(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {}
 
 static void call_destroy_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats, void *ignored) {
+                              const grpc_call_final_info *final_info,
+                              void *ignored) {
   ++*(int *)(elem->channel_data);
 }
 
@@ -132,8 +135,10 @@
   GPR_ASSERT(*channel_data == 0);
 
   call_stack = gpr_malloc(channel_stack->call_stack_size);
-  grpc_call_stack_init(&exec_ctx, channel_stack, 1, free_call, call_stack, NULL,
-                       NULL, call_stack);
+  grpc_error *error =
+      grpc_call_stack_init(&exec_ctx, channel_stack, 1, free_call, call_stack,
+                           NULL, NULL, call_stack);
+  GPR_ASSERT(error == GRPC_ERROR_NONE);
   GPR_ASSERT(call_stack->count == 1);
   call_elem = grpc_call_stack_element(call_stack, 0);
   GPR_ASSERT(call_elem->filter == channel_elem->filter);
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index 890309c..b775680 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -259,9 +259,10 @@
   gpr_strvec_destroy(&have_tags);
 }
 
-void cq_verify_empty(cq_verifier *v) {
-  gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                                       gpr_time_from_seconds(1, GPR_TIMESPAN));
+void cq_verify_empty_timeout(cq_verifier *v, int timeout_sec) {
+  gpr_timespec deadline =
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                   gpr_time_from_seconds(timeout_sec, GPR_TIMESPAN));
   grpc_event ev;
 
   GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
@@ -275,6 +276,8 @@
   }
 }
 
+void cq_verify_empty(cq_verifier *v) { cq_verify_empty_timeout(v, 1); }
+
 static expectation *add(cq_verifier *v, grpc_completion_type type, void *tag) {
   expectation *e = gpr_malloc(sizeof(expectation));
   e->type = type;
diff --git a/test/core/end2end/cq_verifier.h b/test/core/end2end/cq_verifier.h
index 8c9a85c..bf82468 100644
--- a/test/core/end2end/cq_verifier.h
+++ b/test/core/end2end/cq_verifier.h
@@ -55,6 +55,9 @@
 /* ensure that the completion queue is empty */
 void cq_verify_empty(cq_verifier *v);
 
+/* ensure that the completion queue is empty, waiting up to \a timeout secs. */
+void cq_verify_empty_timeout(cq_verifier *v, int timeout_sec);
+
 /* Various expectation matchers
    Any functions taking ... expect a NULL terminated list of key/value pairs
    (each pair using two parameter slots) of metadata that MUST be present in
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 65a8deb..348b9ed 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -273,7 +273,7 @@
 }
 
 int external_dns_works(const char *host) {
-  grpc_resolved_addresses *res;
+  grpc_resolved_addresses *res = NULL;
   grpc_error *error = grpc_blocking_resolve_address(host, "80", &res);
   GRPC_ERROR_UNREF(error);
   if (res != NULL) {
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index 03e55f1..3efd18c 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -69,6 +69,8 @@
 extern void disappearing_server_pre_init(void);
 extern void empty_batch(grpc_end2end_test_config config);
 extern void empty_batch_pre_init(void);
+extern void filter_call_init_fails(grpc_end2end_test_config config);
+extern void filter_call_init_fails_pre_init(void);
 extern void filter_causes_close(grpc_end2end_test_config config);
 extern void filter_causes_close_pre_init(void);
 extern void graceful_server_shutdown(grpc_end2end_test_config config);
@@ -83,6 +85,8 @@
 extern void invoke_large_request_pre_init(void);
 extern void large_metadata(grpc_end2end_test_config config);
 extern void large_metadata_pre_init(void);
+extern void load_reporting_hook(grpc_end2end_test_config config);
+extern void load_reporting_hook_pre_init(void);
 extern void max_concurrent_streams(grpc_end2end_test_config config);
 extern void max_concurrent_streams_pre_init(void);
 extern void max_message_length(grpc_end2end_test_config config);
@@ -138,6 +142,7 @@
   default_host_pre_init();
   disappearing_server_pre_init();
   empty_batch_pre_init();
+  filter_call_init_fails_pre_init();
   filter_causes_close_pre_init();
   graceful_server_shutdown_pre_init();
   high_initial_seqno_pre_init();
@@ -145,6 +150,7 @@
   idempotent_request_pre_init();
   invoke_large_request_pre_init();
   large_metadata_pre_init();
+  load_reporting_hook_pre_init();
   max_concurrent_streams_pre_init();
   max_message_length_pre_init();
   negative_deadline_pre_init();
@@ -186,6 +192,7 @@
     default_host(config);
     disappearing_server(config);
     empty_batch(config);
+    filter_call_init_fails(config);
     filter_causes_close(config);
     graceful_server_shutdown(config);
     high_initial_seqno(config);
@@ -193,6 +200,7 @@
     idempotent_request(config);
     invoke_large_request(config);
     large_metadata(config);
+    load_reporting_hook(config);
     max_concurrent_streams(config);
     max_message_length(config);
     negative_deadline(config);
@@ -268,6 +276,10 @@
       empty_batch(config);
       continue;
     }
+    if (0 == strcmp("filter_call_init_fails", argv[i])) {
+      filter_call_init_fails(config);
+      continue;
+    }
     if (0 == strcmp("filter_causes_close", argv[i])) {
       filter_causes_close(config);
       continue;
@@ -296,6 +308,10 @@
       large_metadata(config);
       continue;
     }
+    if (0 == strcmp("load_reporting_hook", argv[i])) {
+      load_reporting_hook(config);
+      continue;
+    }
     if (0 == strcmp("max_concurrent_streams", argv[i])) {
       max_concurrent_streams(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 877b1b1..e3d791a 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -71,6 +71,8 @@
 extern void disappearing_server_pre_init(void);
 extern void empty_batch(grpc_end2end_test_config config);
 extern void empty_batch_pre_init(void);
+extern void filter_call_init_fails(grpc_end2end_test_config config);
+extern void filter_call_init_fails_pre_init(void);
 extern void filter_causes_close(grpc_end2end_test_config config);
 extern void filter_causes_close_pre_init(void);
 extern void graceful_server_shutdown(grpc_end2end_test_config config);
@@ -85,6 +87,8 @@
 extern void invoke_large_request_pre_init(void);
 extern void large_metadata(grpc_end2end_test_config config);
 extern void large_metadata_pre_init(void);
+extern void load_reporting_hook(grpc_end2end_test_config config);
+extern void load_reporting_hook_pre_init(void);
 extern void max_concurrent_streams(grpc_end2end_test_config config);
 extern void max_concurrent_streams_pre_init(void);
 extern void max_message_length(grpc_end2end_test_config config);
@@ -141,6 +145,7 @@
   default_host_pre_init();
   disappearing_server_pre_init();
   empty_batch_pre_init();
+  filter_call_init_fails_pre_init();
   filter_causes_close_pre_init();
   graceful_server_shutdown_pre_init();
   high_initial_seqno_pre_init();
@@ -148,6 +153,7 @@
   idempotent_request_pre_init();
   invoke_large_request_pre_init();
   large_metadata_pre_init();
+  load_reporting_hook_pre_init();
   max_concurrent_streams_pre_init();
   max_message_length_pre_init();
   negative_deadline_pre_init();
@@ -190,6 +196,7 @@
     default_host(config);
     disappearing_server(config);
     empty_batch(config);
+    filter_call_init_fails(config);
     filter_causes_close(config);
     graceful_server_shutdown(config);
     high_initial_seqno(config);
@@ -197,6 +204,7 @@
     idempotent_request(config);
     invoke_large_request(config);
     large_metadata(config);
+    load_reporting_hook(config);
     max_concurrent_streams(config);
     max_message_length(config);
     negative_deadline(config);
@@ -276,6 +284,10 @@
       empty_batch(config);
       continue;
     }
+    if (0 == strcmp("filter_call_init_fails", argv[i])) {
+      filter_call_init_fails(config);
+      continue;
+    }
     if (0 == strcmp("filter_causes_close", argv[i])) {
       filter_causes_close(config);
       continue;
@@ -304,6 +316,10 @@
       large_metadata(config);
       continue;
     }
+    if (0 == strcmp("load_reporting_hook", argv[i])) {
+      load_reporting_hook(config);
+      continue;
+    }
     if (0 == strcmp("max_concurrent_streams", argv[i])) {
       max_concurrent_streams(config);
       continue;
diff --git a/test/core/end2end/fixtures/h2_load_reporting.c b/test/core/end2end/fixtures/h2_load_reporting.c
new file mode 100644
index 0000000..f6d3923
--- /dev/null
+++ b/test/core/end2end/fixtures/h2_load_reporting.c
@@ -0,0 +1,125 @@
+/*
+ *
+ * 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 "test/core/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+#include "src/core/ext/client_config/client_channel.h"
+#include "src/core/ext/load_reporting/load_reporting.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/channel/connected_channel.h"
+#include "src/core/lib/channel/http_server_filter.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+
+typedef struct load_reporting_fixture_data {
+  char *localaddr;
+} load_reporting_fixture_data;
+
+static grpc_end2end_test_fixture chttp2_create_fixture_load_reporting(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  int port = grpc_pick_unused_port_or_die();
+  load_reporting_fixture_data *ffd =
+      gpr_malloc(sizeof(load_reporting_fixture_data));
+  memset(&f, 0, sizeof(f));
+
+  gpr_join_host_port(&ffd->localaddr, "localhost", port);
+
+  f.fixture_data = ffd;
+  f.cq = grpc_completion_queue_create(NULL);
+
+  return f;
+}
+
+void chttp2_init_client_load_reporting(grpc_end2end_test_fixture *f,
+                                       grpc_channel_args *client_args) {
+  load_reporting_fixture_data *ffd = f->fixture_data;
+  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
+  GPR_ASSERT(f->client);
+}
+
+void chttp2_init_server_load_reporting(grpc_end2end_test_fixture *f,
+                                       grpc_channel_args *server_args) {
+  load_reporting_fixture_data *ffd = f->fixture_data;
+  grpc_arg arg = grpc_load_reporting_enable_arg();
+  if (f->server) {
+    grpc_server_destroy(f->server);
+  }
+  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_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);
+}
+
+void chttp2_tear_down_load_reporting(grpc_end2end_test_fixture *f) {
+  load_reporting_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd->localaddr);
+  gpr_free(ffd);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+    {"chttp2/fullstack+load_reporting",
+     FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
+     chttp2_create_fixture_load_reporting, chttp2_init_client_load_reporting,
+     chttp2_init_server_load_reporting, chttp2_tear_down_load_reporting},
+};
+
+int main(int argc, char **argv) {
+  size_t i;
+
+  grpc_test_init(argc, argv);
+  grpc_end2end_tests_pre_init();
+  grpc_init();
+
+  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
+    grpc_end2end_tests(argc, argv, configs[i]);
+  }
+
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/end2end/fixtures/h2_loadreporting.c b/test/core/end2end/fixtures/h2_loadreporting.c
deleted file mode 100644
index 4ed02f9..0000000
--- a/test/core/end2end/fixtures/h2_loadreporting.c
+++ /dev/null
@@ -1,184 +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.
- *
- */
-
-#include "test/core/end2end/end2end_tests.h"
-
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/host_port.h>
-#include <grpc/support/log.h>
-#include <grpc/support/sync.h>
-#include <grpc/support/thd.h>
-#include <grpc/support/useful.h>
-#include "src/core/ext/client_config/client_channel.h"
-#include "src/core/ext/load_reporting/load_reporting.h"
-#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
-#include "src/core/lib/channel/channel_args.h"
-#include "src/core/lib/channel/connected_channel.h"
-#include "src/core/lib/channel/http_server_filter.h"
-#include "src/core/lib/surface/channel.h"
-#include "src/core/lib/surface/server.h"
-#include "test/core/util/port.h"
-#include "test/core/util/test_config.h"
-
-static grpc_load_reporting_config *g_client_lrc;
-static grpc_load_reporting_config *g_server_lrc;
-
-typedef struct fullstack_fixture_data {
-  char *localaddr;
-} fullstack_fixture_data;
-
-static grpc_end2end_test_fixture chttp2_create_fixture_fullstack(
-    grpc_channel_args *client_args, grpc_channel_args *server_args) {
-  grpc_end2end_test_fixture f;
-  int port = grpc_pick_unused_port_or_die();
-  fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data));
-  memset(&f, 0, sizeof(f));
-
-  gpr_join_host_port(&ffd->localaddr, "localhost", port);
-
-  f.fixture_data = ffd;
-  f.cq = grpc_completion_queue_create(NULL);
-
-  return f;
-}
-
-typedef struct {
-  int64_t total_bytes;
-  bool fully_processed;
-  uint32_t initial_token;
-  uint32_t final_token;
-} aggregated_bw_stats;
-
-static void sample_fn(const grpc_load_reporting_call_data *call_data,
-                      void *user_data) {
-  GPR_ASSERT(user_data != NULL);
-  aggregated_bw_stats *custom_stats = (aggregated_bw_stats *)user_data;
-  if (call_data == NULL) {
-    /* initial invocation */
-    custom_stats->initial_token = 0xDEADBEEF;
-  } else {
-    /* final invocation */
-    custom_stats->total_bytes =
-        (int64_t)(call_data->stats->transport_stream_stats.outgoing.data_bytes +
-                  call_data->stats->transport_stream_stats.incoming.data_bytes);
-    custom_stats->final_token = 0xCAFED00D;
-    custom_stats->fully_processed = true;
-  }
-}
-
-void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
-                                  grpc_channel_args *client_args) {
-  fullstack_fixture_data *ffd = f->fixture_data;
-  grpc_arg arg = grpc_load_reporting_config_create_arg(g_client_lrc);
-  client_args = grpc_channel_args_copy_and_add(client_args, &arg, 1);
-  f->client = grpc_insecure_channel_create(ffd->localaddr, client_args, NULL);
-  grpc_channel_args_destroy(client_args);
-  GPR_ASSERT(f->client);
-}
-
-void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f,
-                                  grpc_channel_args *server_args) {
-  fullstack_fixture_data *ffd = f->fixture_data;
-  if (f->server) {
-    grpc_server_destroy(f->server);
-  }
-  grpc_arg arg = grpc_load_reporting_config_create_arg(g_server_lrc);
-  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_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);
-}
-
-void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) {
-  fullstack_fixture_data *ffd = f->fixture_data;
-  gpr_free(ffd->localaddr);
-  gpr_free(ffd);
-}
-
-/* All test configurations */
-static grpc_end2end_test_config configs[] = {
-    {"chttp2/fullstack+loadreporting", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION,
-     chttp2_create_fixture_fullstack, chttp2_init_client_fullstack,
-     chttp2_init_server_fullstack, chttp2_tear_down_fullstack},
-};
-
-int main(int argc, char **argv) {
-  size_t i;
-
-  aggregated_bw_stats *aggr_stats_client =
-      gpr_malloc(sizeof(aggregated_bw_stats));
-  aggr_stats_client->total_bytes = -1;
-  aggr_stats_client->fully_processed = false;
-  aggregated_bw_stats *aggr_stats_server =
-      gpr_malloc(sizeof(aggregated_bw_stats));
-  aggr_stats_server->total_bytes = -1;
-  aggr_stats_server->fully_processed = false;
-
-  g_client_lrc =
-      grpc_load_reporting_config_create(sample_fn, aggr_stats_client);
-  g_server_lrc =
-      grpc_load_reporting_config_create(sample_fn, aggr_stats_server);
-
-  grpc_test_init(argc, argv);
-  grpc_end2end_tests_pre_init();
-  grpc_init();
-
-  for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
-    grpc_end2end_tests(argc, argv, configs[i]);
-  }
-
-  grpc_shutdown();
-
-  grpc_load_reporting_config_destroy(g_client_lrc);
-  grpc_load_reporting_config_destroy(g_server_lrc);
-
-  if (aggr_stats_client->fully_processed) {
-    GPR_ASSERT(aggr_stats_client->total_bytes >= 0);
-    GPR_ASSERT(aggr_stats_client->initial_token == 0xDEADBEEF);
-    GPR_ASSERT(aggr_stats_client->final_token == 0xCAFED00D);
-  }
-  if (aggr_stats_server->fully_processed) {
-    GPR_ASSERT(aggr_stats_server->total_bytes >= 0);
-    GPR_ASSERT(aggr_stats_server->initial_token == 0xDEADBEEF);
-    GPR_ASSERT(aggr_stats_server->final_token == 0xCAFED00D);
-  }
-
-  gpr_free(aggr_stats_client);
-  gpr_free(aggr_stats_server);
-
-  return 0;
-}
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 6b0769b..b8a5257 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -108,7 +108,7 @@
       grpc_create_chttp2_transport(&exec_ctx, client_args, sfd->client, 1);
   client_setup_transport(&exec_ctx, &cs, transport);
   GPR_ASSERT(f->client);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -124,7 +124,7 @@
   transport =
       grpc_create_chttp2_transport(&exec_ctx, server_args, sfd->server, 0);
   server_setup_transport(f, transport);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index 7be88f8..a57990d 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -107,7 +107,7 @@
       grpc_create_chttp2_transport(&exec_ctx, client_args, sfd->client, 1);
   client_setup_transport(&exec_ctx, &cs, transport);
   GPR_ASSERT(f->client);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -123,7 +123,7 @@
   transport =
       grpc_create_chttp2_transport(&exec_ctx, server_args, sfd->server, 0);
   server_setup_transport(f, transport);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 166654b..50aac80 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -107,7 +107,7 @@
       grpc_create_chttp2_transport(&exec_ctx, client_args, sfd->client, 1);
   client_setup_transport(&exec_ctx, &cs, transport);
   GPR_ASSERT(f->client);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -123,7 +123,7 @@
   transport =
       grpc_create_chttp2_transport(&exec_ctx, server_args, sfd->server, 0);
   server_setup_transport(f, transport);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
diff --git a/test/core/end2end/fuzzers/api_fuzzer.c b/test/core/end2end/fuzzers/api_fuzzer.c
index 13b8bf7..96ea82d 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.c
+++ b/test/core/end2end/fuzzers/api_fuzzer.c
@@ -258,7 +258,7 @@
     grpc_transport *transport =
         grpc_create_chttp2_transport(exec_ctx, NULL, server, 0);
     grpc_server_setup_transport(exec_ctx, g_server, transport, NULL, NULL);
-    grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL, 0);
+    grpc_chttp2_transport_start_reading(exec_ctx, transport, NULL);
 
     grpc_exec_ctx_sched(exec_ctx, fc->closure, GRPC_ERROR_NONE, NULL);
   } else {
diff --git a/test/core/end2end/fuzzers/client_fuzzer.c b/test/core/end2end/fuzzers/client_fuzzer.c
index 79b23d7..00e650a 100644
--- a/test/core/end2end/fuzzers/client_fuzzer.c
+++ b/test/core/end2end/fuzzers/client_fuzzer.c
@@ -63,7 +63,7 @@
   grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
   grpc_transport *transport =
       grpc_create_chttp2_transport(&exec_ctx, NULL, mock_endpoint, 1);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
 
   grpc_channel *channel = grpc_channel_create(
       &exec_ctx, "test-target", NULL, GRPC_CLIENT_DIRECT_CHANNEL, transport);
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index 097e9a8..3157dfc 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -21,8 +21,6 @@
 "\x0A:authority"
 "\x0Dauthorization"
 "\x0Dcache-control"
-"\x0Acensus-bin"
-"\x11census-binary-bin"
 "\x13content-disposition"
 "\x10content-encoding"
 "\x10content-language"
@@ -42,11 +40,13 @@
 "\x03GET"
 "\x04grpc"
 "\x14grpc-accept-encoding"
+"\x0Fgrpc-census-bin"
 "\x0Dgrpc-encoding"
 "\x1Egrpc-internal-encoding-request"
 "\x0Cgrpc-message"
 "\x0Bgrpc-status"
 "\x0Cgrpc-timeout"
+"\x10grpc-tracing-bin"
 "\x04gzip"
 "\x0Dgzip, deflate"
 "\x04host"
@@ -63,7 +63,8 @@
 "\x13if-unmodified-since"
 "\x0Dlast-modified"
 "\x04link"
-"\x0Eload-reporting"
+"\x16load-reporting-initial"
+"\x17load-reporting-trailing"
 "\x08location"
 "\x0Cmax-forwards"
 "\x07:method"
@@ -137,7 +138,8 @@
 "\x00\x13if-unmodified-since\x00"
 "\x00\x0Dlast-modified\x00"
 "\x00\x04link\x00"
-"\x00\x0Eload-reporting\x00"
+"\x00\x16load-reporting-initial\x00"
+"\x00\x17load-reporting-trailing\x00"
 "\x00\x08location\x00"
 "\x00\x0Cmax-forwards\x00"
 "\x00\x07:method\x03GET"
diff --git a/test/core/end2end/fuzzers/server_fuzzer.c b/test/core/end2end/fuzzers/server_fuzzer.c
index 80f568a..79eaad7 100644
--- a/test/core/end2end/fuzzers/server_fuzzer.c
+++ b/test/core/end2end/fuzzers/server_fuzzer.c
@@ -71,7 +71,7 @@
   grpc_transport *transport =
       grpc_create_chttp2_transport(&exec_ctx, NULL, mock_endpoint, 0);
   grpc_server_setup_transport(&exec_ctx, server, transport, NULL, NULL);
-  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(&exec_ctx, transport, NULL);
 
   grpc_call *call1 = NULL;
   grpc_call_details call_details1;
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index fb72754..e59b7dc 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -53,13 +53,13 @@
 END2END_FIXTURES = {
     'h2_compress': default_unsecure_fixture_options,
     'h2_census': default_unsecure_fixture_options,
+    'h2_load_reporting': default_unsecure_fixture_options,
     'h2_fakesec': default_secure_fixture_options._replace(ci_mac=False),
     'h2_fd': fd_unsecure_fixture_options,
     'h2_full': default_unsecure_fixture_options,
     'h2_full+pipe': default_unsecure_fixture_options._replace(
         platforms=['linux']),
     'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True),
-    'h2_loadreporting': default_unsecure_fixture_options,
     'h2_oauth2': default_secure_fixture_options._replace(ci_mac=False),
     'h2_proxy': default_unsecure_fixture_options._replace(includes_proxy=True,
                                                           ci_mac=False),
@@ -102,6 +102,7 @@
     'disappearing_server': connectivity_test_options,
     'empty_batch': default_test_options,
     'filter_causes_close': default_test_options,
+    'filter_call_init_fails': default_test_options,
     'graceful_server_shutdown': default_test_options._replace(cpu_cost=LOWCPU),
     'hpack_size': default_test_options._replace(proxyable=False,
                                                 traceable=False),
@@ -115,6 +116,7 @@
     'network_status_change': default_test_options,
     'no_op': default_test_options,
     'payload': default_test_options,
+    'load_reporting_hook': default_test_options,
     'ping_pong_streaming': default_test_options,
     'ping': connectivity_test_options._replace(proxyable=False),
     'registered_call': default_test_options,
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
new file mode 100644
index 0000000..a09183b
--- /dev/null
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -0,0 +1,273 @@
+/*
+ *
+ * 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 "test/core/end2end/end2end_tests.h"
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "test/core/end2end/cq_verifier.h"
+
+enum { TIMEOUT = 200000 };
+
+static bool g_enable_filter = false;
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char *test_name,
+                                            grpc_channel_args *client_args,
+                                            grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+}
+
+// Simple request via a server filter that always fails to initialize
+// the call.
+static void test_request(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_call *s;
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  grpc_end2end_test_fixture f =
+      begin_test(config, "filter_call_init_fails", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  char *details = NULL;
+  size_t details_capacity = 0;
+
+  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               "/foo", "foo.test.google.fr", deadline, NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == strcmp(details, "access denied"));
+
+  gpr_free(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+/*******************************************************************************
+ * Test filter - always fails to initialize a call
+ */
+
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
+  return grpc_error_set_int(GRPC_ERROR_CREATE("access denied"),
+                            GRPC_ERROR_INT_GRPC_STATUS,
+                            GRPC_STATUS_PERMISSION_DENIED);
+}
+
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              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 void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem) {}
+
+static const grpc_channel_filter test_filter = {
+    grpc_call_next_op,
+    grpc_channel_next_op,
+    0,
+    init_call_elem,
+    grpc_call_stack_ignore_set_pollset_or_pollset_set,
+    destroy_call_elem,
+    0,
+    init_channel_elem,
+    destroy_channel_elem,
+    grpc_call_next_get_peer,
+    "filter_call_init_fails"};
+
+/*******************************************************************************
+ * Registration
+ */
+
+static bool maybe_add_filter(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
+    // can't add it at the very end, because the connected channel filter
+    // must be the last one.  So we add it right before the last one.
+    grpc_channel_stack_builder_iterator *it =
+        grpc_channel_stack_builder_create_iterator_at_last(builder);
+    GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
+    const bool retval = grpc_channel_stack_builder_add_filter_before(
+        it, &test_filter, NULL, NULL);
+    grpc_channel_stack_builder_iterator_destroy(it);
+    return retval;
+  } else {
+    return true;
+  }
+}
+
+static void init_plugin(void) {
+  grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
+                                   maybe_add_filter, NULL);
+}
+
+static void destroy_plugin(void) {}
+
+void filter_call_init_fails(grpc_end2end_test_config config) {
+  g_enable_filter = true;
+  test_request(config);
+  g_enable_filter = false;
+}
+
+void filter_call_init_fails_pre_init(void) {
+  grpc_register_plugin(init_plugin, destroy_plugin);
+}
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index 526c05c..c6c36d6 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -233,11 +233,14 @@
   grpc_call_next_op(exec_ctx, elem, op);
 }
 
-static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                           grpc_call_element_args *args) {}
+static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem,
+                                  grpc_call_element_args *args) {
+  return GRPC_ERROR_NONE;
+}
 
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_stats *stats,
+                              const grpc_call_final_info *final_info,
                               void *and_free_memory) {}
 
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
new file mode 100644
index 0000000..2c65198
--- /dev/null
+++ b/test/core/end2end/tests/load_reporting_hook.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 "test/core/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "test/core/end2end/cq_verifier.h"
+
+#include "src/core/ext/load_reporting/load_reporting.h"
+#include "src/core/ext/load_reporting/load_reporting_filter.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+typedef struct {
+  gpr_mu mu;
+  intptr_t channel_id;
+  intptr_t call_id;
+
+  char *initial_md_str;
+  char *trailing_md_str;
+  char *method_name;
+
+  uint64_t incoming_bytes;
+  uint64_t outgoing_bytes;
+
+  grpc_status_code call_final_status;
+
+  bool fully_processed;
+} load_reporting_data;
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char *test_name,
+                                            grpc_channel_args *client_args,
+                                            grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+}
+
+static void request_response_with_payload(grpc_end2end_test_fixture f,
+                                          const char *method_name,
+                                          const char *request_msg,
+                                          const char *response_msg,
+                                          grpc_metadata *initial_lr_metadata,
+                                          grpc_metadata *trailing_lr_metadata) {
+  gpr_slice request_payload_slice = gpr_slice_from_static_string(request_msg);
+  gpr_slice response_payload_slice = gpr_slice_from_static_string(response_msg);
+  grpc_call *c;
+  grpc_call *s;
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer *response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_byte_buffer *response_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  char *details = NULL;
+  size_t details_capacity = 0;
+  int was_cancelled = 2;
+
+  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               method_name, "foo.test.google.fr", deadline,
+                               NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  GPR_ASSERT(initial_lr_metadata != NULL);
+  op->data.send_initial_metadata.count = 1;
+  op->data.send_initial_metadata.metadata = initial_lr_metadata;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &response_payload_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  cq_expect_completion(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &request_payload_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(102), 1);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message = response_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  GPR_ASSERT(trailing_lr_metadata != NULL);
+  op->data.send_status_from_server.trailing_metadata_count = 1;
+  op->data.send_status_from_server.trailing_metadata = trailing_lr_metadata;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(103), 1);
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+
+  gpr_free(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+}
+
+/* override the default for testing purposes */
+extern void (*g_load_reporting_fn)(
+    const grpc_load_reporting_call_data *call_data);
+
+static void test_load_reporting_hook(grpc_end2end_test_config config) {
+  /* TODO(dgq): this test is currently a noop until LR is fully defined.
+   * Leaving the rest here, as it'll likely be reusable. */
+
+  /* Introduce load reporting for the server through its arguments */
+  grpc_arg arg = grpc_load_reporting_enable_arg();
+  grpc_channel_args *lr_server_args =
+      grpc_channel_args_copy_and_add(NULL, &arg, 1);
+
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_load_reporting_hook", NULL, lr_server_args);
+
+  const char *method_name = "/gRPCFTW";
+  const char *request_msg = "the msg from the client";
+  const char *response_msg = "... and the response from the server";
+
+  grpc_metadata initial_lr_metadata;
+  grpc_metadata trailing_lr_metadata;
+
+  initial_lr_metadata.key = GRPC_LOAD_REPORTING_INITIAL_MD_KEY;
+  initial_lr_metadata.value = "client-token";
+  initial_lr_metadata.value_length = strlen(initial_lr_metadata.value);
+  memset(&initial_lr_metadata.internal_data, 0,
+         sizeof(initial_lr_metadata.internal_data));
+
+  trailing_lr_metadata.key = GRPC_LOAD_REPORTING_TRAILING_MD_KEY;
+  trailing_lr_metadata.value = "server-token";
+  trailing_lr_metadata.value_length = strlen(trailing_lr_metadata.value);
+  memset(&trailing_lr_metadata.internal_data, 0,
+         sizeof(trailing_lr_metadata.internal_data));
+
+  request_response_with_payload(f, method_name, request_msg, response_msg,
+                                &initial_lr_metadata, &trailing_lr_metadata);
+  end_test(&f);
+  grpc_channel_args_destroy(lr_server_args);
+  config.tear_down_data(&f);
+}
+
+void load_reporting_hook(grpc_end2end_test_config config) {
+  test_load_reporting_hook(config);
+}
+
+void load_reporting_hook_pre_init(void) {}
diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c
index 3152fb7..a959a7e 100644
--- a/test/core/iomgr/udp_server_test.c
+++ b/test/core/iomgr/udp_server_test.c
@@ -70,7 +70,8 @@
   g_number_of_reads++;
   g_number_of_bytes_read += (int)byte_count;
 
-  grpc_pollset_kick(g_pollset, NULL);
+  GPR_ASSERT(
+      GRPC_LOG_IF_ERROR("pollset_kick", grpc_pollset_kick(g_pollset, NULL)));
   gpr_mu_unlock(g_mu);
 }
 
@@ -179,8 +180,10 @@
     while (g_number_of_reads == number_of_reads_before &&
            gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0) {
       grpc_pollset_worker *worker = NULL;
-      grpc_pollset_work(&exec_ctx, g_pollset, &worker,
-                        gpr_now(GPR_CLOCK_MONOTONIC), deadline);
+      GPR_ASSERT(GRPC_LOG_IF_ERROR(
+          "pollset_work",
+          grpc_pollset_work(&exec_ctx, g_pollset, &worker,
+                            gpr_now(GPR_CLOCK_MONOTONIC), deadline)));
       gpr_mu_unlock(g_mu);
       grpc_exec_ctx_finish(&exec_ctx);
       gpr_mu_lock(g_mu);
@@ -199,7 +202,8 @@
   GPR_ASSERT(g_number_of_orphan_calls == 1);
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p,
+                            grpc_error *error) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/json/json_test.c b/test/core/json/json_test.c
index ac1abbd..7ea5cac 100644
--- a/test/core/json/json_test.c
+++ b/test/core/json/json_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/core/nanopb/fuzzer_response.c b/test/core/nanopb/fuzzer_response.c
index 21a5d7b..75a99fa 100644
--- a/test/core/nanopb/fuzzer_response.c
+++ b/test/core/nanopb/fuzzer_response.c
@@ -43,9 +43,9 @@
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   gpr_slice slice = gpr_slice_from_copied_buffer((const char *)data, size);
-  grpc_grpclb_response *response;
-  if ((response = grpc_grpclb_response_parse(slice))) {
-    grpc_grpclb_response_destroy(response);
+  grpc_grpclb_initial_response *response;
+  if ((response = grpc_grpclb_initial_response_parse(slice))) {
+    grpc_grpclb_initial_response_destroy(response);
   }
   gpr_slice_unref(slice);
   return 0;
diff --git a/test/core/support/slice_test.c b/test/core/support/slice_test.c
index 0da483a..06c364b 100644
--- a/test/core/support/slice_test.c
+++ b/test/core/support/slice_test.c
@@ -85,6 +85,27 @@
   gpr_slice_unref(slice);
 }
 
+/* destroy function that sets a mark to indicate it was called. */
+static void set_mark(void *p) { *((int *)p) = 1; }
+
+static void test_slice_new_with_user_data(void) {
+  int marker = 0;
+  uint8_t buf[2];
+  gpr_slice slice;
+
+  buf[0] = 0;
+  buf[1] = 1;
+  slice = gpr_slice_new_with_user_data(buf, 2, set_mark, &marker);
+  GPR_ASSERT(marker == 0);
+  GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 2);
+  GPR_ASSERT(GPR_SLICE_START_PTR(slice)[0] == 0);
+  GPR_ASSERT(GPR_SLICE_START_PTR(slice)[1] == 1);
+
+  /* unref should cause destroy function to run. */
+  gpr_slice_unref(slice);
+  GPR_ASSERT(marker == 1);
+}
+
 static int do_nothing_with_len_1_calls = 0;
 
 static void do_nothing_with_len_1(void *ignored, size_t len) {
@@ -232,6 +253,7 @@
   grpc_test_init(argc, argv);
   test_slice_malloc_returns_something_sensible();
   test_slice_new_returns_something_sensible();
+  test_slice_new_with_user_data();
   test_slice_new_with_len_returns_something_sensible();
   for (length = 0; length < 128; length++) {
     test_slice_sub_works(length);
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/timeout_encoding_test.c
similarity index 89%
rename from test/core/transport/chttp2/timeout_encoding_test.c
rename to test/core/transport/timeout_encoding_test.c
index 6763993..b6004af 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/timeout_encoding_test.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/ext/transport/chttp2/transport/timeout_encoding.h"
+#include "src/core/lib/transport/timeout_encoding.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -46,8 +46,8 @@
 #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
 
 static void assert_encodes_as(gpr_timespec ts, const char *s) {
-  char buffer[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
-  grpc_chttp2_encode_timeout(ts, buffer);
+  char buffer[GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
+  grpc_http2_encode_timeout(ts, buffer);
   gpr_log(GPR_INFO, "check '%s' == '%s'", buffer, s);
   GPR_ASSERT(0 == strcmp(buffer, s));
 }
@@ -88,7 +88,7 @@
 static void assert_decodes_as(const char *buffer, gpr_timespec expected) {
   gpr_timespec got;
   gpr_log(GPR_INFO, "check decoding '%s'", buffer);
-  GPR_ASSERT(1 == grpc_chttp2_decode_timeout(buffer, &got));
+  GPR_ASSERT(1 == grpc_http2_decode_timeout(buffer, &got));
   GPR_ASSERT(0 == gpr_time_cmp(got, expected));
 }
 
@@ -137,15 +137,15 @@
 void test_decoding_fails(void) {
   gpr_timespec x;
   LOG_TEST("test_decoding_fails");
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout(" ", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("x", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("1", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("1x", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("1ux", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("!", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("n1", &x));
-  GPR_ASSERT(0 == grpc_chttp2_decode_timeout("-1u", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout(" ", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("x", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("1", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("1x", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("1ux", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("!", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("n1", &x));
+  GPR_ASSERT(0 == grpc_http2_decode_timeout("-1u", &x));
 }
 
 int main(int argc, char **argv) {
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 4a8936d..ac79fe8 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -200,6 +200,10 @@
   bool spin_;
 };
 
+bool plugin_has_sync_methods(std::unique_ptr<ServerBuilderPlugin>& plugin) {
+  return plugin->has_sync_methods();
+}
+
 // This class disables the server builder plugins that may add sync services to
 // the server. If there are sync services, UnimplementedRpc test will triger
 // the sync unkown rpc routine on the server side, rather than the async one
@@ -210,14 +214,9 @@
 
   void UpdatePlugins(std::vector<std::unique_ptr<ServerBuilderPlugin>>* plugins)
       GRPC_OVERRIDE {
-    auto plugin = plugins->begin();
-    while (plugin != plugins->end()) {
-      if ((*plugin)->has_sync_methods()) {
-        plugins->erase(plugin++);
-      } else {
-        plugin++;
-      }
-    }
+    plugins->erase(std::remove_if(plugins->begin(), plugins->end(),
+                                  plugin_has_sync_methods),
+                   plugins->end());
   }
 };
 
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 0f87ae3..46a58d3 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -1414,7 +1414,7 @@
   std::shared_ptr<const AuthContext> auth_ctx = context.auth_context();
   std::vector<grpc::string_ref> tst =
       auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1u, tst.size());
+  ASSERT_EQ(1u, tst.size());
   EXPECT_EQ(GetParam().credentials_type, ToString(tst[0]));
   if (GetParam().credentials_type == kTlsCredentialsType) {
     EXPECT_EQ("x509_subject_alternative_name",
diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc
new file mode 100644
index 0000000..853720f
--- /dev/null
+++ b/test/cpp/end2end/filter_end2end_test.cc
@@ -0,0 +1,353 @@
+/*
+ *
+ * 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 <memory>
+#include <mutex>
+
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/generic/async_generic_service.h>
+#include <grpc++/generic/generic_stub.h>
+#include <grpc++/impl/codegen/proto_utils.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc++/support/config.h>
+#include <grpc++/support/slice.h>
+#include <grpc/grpc.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+#include <gtest/gtest.h>
+
+#include "src/cpp/common/channel_filter.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+
+using grpc::testing::EchoRequest;
+using grpc::testing::EchoResponse;
+using std::chrono::system_clock;
+
+namespace grpc {
+namespace testing {
+namespace {
+
+void* tag(int i) { return (void*)(intptr_t)i; }
+
+void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
+  bool ok;
+  void* got_tag;
+  EXPECT_TRUE(cq->Next(&got_tag, &ok));
+  EXPECT_EQ(expect_ok, ok);
+  EXPECT_EQ(tag(i), got_tag);
+}
+
+namespace {
+
+int global_num_connections = 0;
+int global_num_calls = 0;
+mutex global_mu;
+
+void IncrementConnectionCounter() {
+  unique_lock<mutex> lock(global_mu);
+  ++global_num_connections;
+}
+
+void ResetConnectionCounter() {
+  unique_lock<mutex> lock(global_mu);
+  global_num_connections = 0;
+}
+
+int GetConnectionCounterValue() {
+  unique_lock<mutex> lock(global_mu);
+  return global_num_connections;
+}
+
+void IncrementCallCounter() {
+  unique_lock<mutex> lock(global_mu);
+  ++global_num_calls;
+}
+
+void ResetCallCounter() {
+  unique_lock<mutex> lock(global_mu);
+  global_num_calls = 0;
+}
+
+int GetCallCounterValue() {
+  unique_lock<mutex> lock(global_mu);
+  return global_num_calls;
+}
+
+}  // namespace
+
+class ChannelDataImpl : public ChannelData {
+ public:
+  ChannelDataImpl(const grpc_channel_args& args, const char* peer)
+      : ChannelData(args, peer) {
+    IncrementConnectionCounter();
+  }
+};
+
+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) GRPC_OVERRIDE {
+    // Incrementing the counter could be done from the ctor, 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());
+  }
+};
+
+class FilterEnd2endTest : public ::testing::Test {
+ protected:
+  FilterEnd2endTest() : server_host_("localhost") {}
+
+  void SetUp() GRPC_OVERRIDE {
+    int port = grpc_pick_unused_port_or_die();
+    server_address_ << server_host_ << ":" << port;
+    // Setup server
+    ServerBuilder builder;
+    builder.AddListeningPort(server_address_.str(),
+                             InsecureServerCredentials());
+    builder.RegisterAsyncGenericService(&generic_service_);
+    srv_cq_ = builder.AddCompletionQueue();
+    server_ = builder.BuildAndStart();
+  }
+
+  void TearDown() GRPC_OVERRIDE {
+    server_->Shutdown();
+    void* ignored_tag;
+    bool ignored_ok;
+    cli_cq_.Shutdown();
+    srv_cq_->Shutdown();
+    while (cli_cq_.Next(&ignored_tag, &ignored_ok))
+      ;
+    while (srv_cq_->Next(&ignored_tag, &ignored_ok))
+      ;
+  }
+
+  void ResetStub() {
+    std::shared_ptr<Channel> channel =
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
+    generic_stub_.reset(new GenericStub(channel));
+    ResetConnectionCounter();
+    ResetCallCounter();
+  }
+
+  void server_ok(int i) { verify_ok(srv_cq_.get(), i, true); }
+  void client_ok(int i) { verify_ok(&cli_cq_, i, true); }
+  void server_fail(int i) { verify_ok(srv_cq_.get(), i, false); }
+  void client_fail(int i) { verify_ok(&cli_cq_, i, false); }
+
+  void SendRpc(int num_rpcs) {
+    const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo");
+    for (int i = 0; i < num_rpcs; i++) {
+      EchoRequest send_request;
+      EchoRequest recv_request;
+      EchoResponse send_response;
+      EchoResponse recv_response;
+      Status recv_status;
+
+      ClientContext cli_ctx;
+      GenericServerContext srv_ctx;
+      GenericServerAsyncReaderWriter stream(&srv_ctx);
+
+      // The string needs to be long enough to test heap-based slice.
+      send_request.set_message("Hello world. Hello world. Hello world.");
+      std::unique_ptr<GenericClientAsyncReaderWriter> call =
+          generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
+      client_ok(1);
+      std::unique_ptr<ByteBuffer> send_buffer =
+          SerializeToByteBuffer(&send_request);
+      call->Write(*send_buffer, tag(2));
+      // Send ByteBuffer can be destroyed after calling Write.
+      send_buffer.reset();
+      client_ok(2);
+      call->WritesDone(tag(3));
+      client_ok(3);
+
+      generic_service_.RequestCall(&srv_ctx, &stream, srv_cq_.get(),
+                                   srv_cq_.get(), tag(4));
+
+      verify_ok(srv_cq_.get(), 4, true);
+      EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length()));
+      EXPECT_EQ(kMethodName, srv_ctx.method());
+      ByteBuffer recv_buffer;
+      stream.Read(&recv_buffer, tag(5));
+      server_ok(5);
+      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
+      EXPECT_EQ(send_request.message(), recv_request.message());
+
+      send_response.set_message(recv_request.message());
+      send_buffer = SerializeToByteBuffer(&send_response);
+      stream.Write(*send_buffer, tag(6));
+      send_buffer.reset();
+      server_ok(6);
+
+      stream.Finish(Status::OK, tag(7));
+      server_ok(7);
+
+      recv_buffer.Clear();
+      call->Read(&recv_buffer, tag(8));
+      client_ok(8);
+      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
+
+      call->Finish(&recv_status, tag(9));
+      client_ok(9);
+
+      EXPECT_EQ(send_response.message(), recv_response.message());
+      EXPECT_TRUE(recv_status.ok());
+    }
+  }
+
+  CompletionQueue cli_cq_;
+  std::unique_ptr<ServerCompletionQueue> srv_cq_;
+  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+  std::unique_ptr<grpc::GenericStub> generic_stub_;
+  std::unique_ptr<Server> server_;
+  AsyncGenericService generic_service_;
+  const grpc::string server_host_;
+  std::ostringstream server_address_;
+};
+
+TEST_F(FilterEnd2endTest, SimpleRpc) {
+  ResetStub();
+  EXPECT_EQ(0, GetConnectionCounterValue());
+  EXPECT_EQ(0, GetCallCounterValue());
+  SendRpc(1);
+  EXPECT_EQ(1, GetConnectionCounterValue());
+  EXPECT_EQ(1, GetCallCounterValue());
+}
+
+TEST_F(FilterEnd2endTest, SequentialRpcs) {
+  ResetStub();
+  EXPECT_EQ(0, GetConnectionCounterValue());
+  EXPECT_EQ(0, GetCallCounterValue());
+  SendRpc(10);
+  EXPECT_EQ(1, GetConnectionCounterValue());
+  EXPECT_EQ(10, GetCallCounterValue());
+}
+
+// One ping, one pong.
+TEST_F(FilterEnd2endTest, SimpleBidiStreaming) {
+  ResetStub();
+  EXPECT_EQ(0, GetConnectionCounterValue());
+  EXPECT_EQ(0, GetCallCounterValue());
+
+  const grpc::string kMethodName(
+      "/grpc.cpp.test.util.EchoTestService/BidiStream");
+  EchoRequest send_request;
+  EchoRequest recv_request;
+  EchoResponse send_response;
+  EchoResponse recv_response;
+  Status recv_status;
+  ClientContext cli_ctx;
+  GenericServerContext srv_ctx;
+  GenericServerAsyncReaderWriter srv_stream(&srv_ctx);
+
+  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
+  send_request.set_message("Hello");
+  std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
+      generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
+  client_ok(1);
+
+  generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(),
+                               srv_cq_.get(), tag(2));
+
+  verify_ok(srv_cq_.get(), 2, true);
+  EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length()));
+  EXPECT_EQ(kMethodName, srv_ctx.method());
+
+  std::unique_ptr<ByteBuffer> send_buffer =
+      SerializeToByteBuffer(&send_request);
+  cli_stream->Write(*send_buffer, tag(3));
+  send_buffer.reset();
+  client_ok(3);
+
+  ByteBuffer recv_buffer;
+  srv_stream.Read(&recv_buffer, tag(4));
+  server_ok(4);
+  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
+  EXPECT_EQ(send_request.message(), recv_request.message());
+
+  send_response.set_message(recv_request.message());
+  send_buffer = SerializeToByteBuffer(&send_response);
+  srv_stream.Write(*send_buffer, tag(5));
+  send_buffer.reset();
+  server_ok(5);
+
+  cli_stream->Read(&recv_buffer, tag(6));
+  client_ok(6);
+  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
+  EXPECT_EQ(send_response.message(), recv_response.message());
+
+  cli_stream->WritesDone(tag(7));
+  client_ok(7);
+
+  srv_stream.Read(&recv_buffer, tag(8));
+  server_fail(8);
+
+  srv_stream.Finish(Status::OK, tag(9));
+  server_ok(9);
+
+  cli_stream->Finish(&recv_status, tag(10));
+  client_ok(10);
+
+  EXPECT_EQ(send_response.message(), recv_response.message());
+  EXPECT_TRUE(recv_status.ok());
+
+  EXPECT_EQ(1, GetCallCounterValue());
+  EXPECT_EQ(1, GetConnectionCounterValue());
+}
+
+void RegisterFilter() {
+  grpc::RegisterChannelFilter<ChannelDataImpl, CallDataImpl>(
+      "test-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr);
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc::testing::RegisterFilter();
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc
index f8fc39b..efbb0e1 100644
--- a/test/cpp/end2end/proto_server_reflection_test.cc
+++ b/test/cpp/end2end/proto_server_reflection_test.cc
@@ -31,7 +31,6 @@
  *
  */
 
-#include <google/protobuf/descriptor.h>
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
@@ -59,7 +58,7 @@
 
   void SetUp() GRPC_OVERRIDE {
     port_ = grpc_pick_unused_port_or_die();
-    ref_desc_pool_ = google::protobuf::DescriptorPool::generated_pool();
+    ref_desc_pool_ = protobuf::DescriptorPool::generated_pool();
 
     ServerBuilder builder;
     grpc::string server_address = "localhost:" + to_string(port_);
@@ -73,7 +72,7 @@
         CreateChannel(target, InsecureChannelCredentials());
     stub_ = grpc::testing::EchoTestService::NewStub(channel);
     desc_db_.reset(new ProtoReflectionDescriptorDatabase(channel));
-    desc_pool_.reset(new google::protobuf::DescriptorPool(desc_db_.get()));
+    desc_pool_.reset(new protobuf::DescriptorPool(desc_db_.get()));
   }
 
   string to_string(const int number) {
@@ -83,15 +82,15 @@
   }
 
   void CompareService(const grpc::string& service) {
-    const google::protobuf::ServiceDescriptor* service_desc =
+    const protobuf::ServiceDescriptor* service_desc =
         desc_pool_->FindServiceByName(service);
-    const google::protobuf::ServiceDescriptor* ref_service_desc =
+    const protobuf::ServiceDescriptor* ref_service_desc =
         ref_desc_pool_->FindServiceByName(service);
     EXPECT_TRUE(service_desc != nullptr);
     EXPECT_TRUE(ref_service_desc != nullptr);
     EXPECT_EQ(service_desc->DebugString(), ref_service_desc->DebugString());
 
-    const google::protobuf::FileDescriptor* file_desc = service_desc->file();
+    const protobuf::FileDescriptor* file_desc = service_desc->file();
     if (known_files_.find(file_desc->package() + "/" + file_desc->name()) !=
         known_files_.end()) {
       EXPECT_EQ(file_desc->DebugString(),
@@ -105,9 +104,9 @@
   }
 
   void CompareMethod(const grpc::string& method) {
-    const google::protobuf::MethodDescriptor* method_desc =
+    const protobuf::MethodDescriptor* method_desc =
         desc_pool_->FindMethodByName(method);
-    const google::protobuf::MethodDescriptor* ref_method_desc =
+    const protobuf::MethodDescriptor* ref_method_desc =
         ref_desc_pool_->FindMethodByName(method);
     EXPECT_TRUE(method_desc != nullptr);
     EXPECT_TRUE(ref_method_desc != nullptr);
@@ -122,9 +121,8 @@
       return;
     }
 
-    const google::protobuf::Descriptor* desc =
-        desc_pool_->FindMessageTypeByName(type);
-    const google::protobuf::Descriptor* ref_desc =
+    const protobuf::Descriptor* desc = desc_pool_->FindMessageTypeByName(type);
+    const protobuf::Descriptor* ref_desc =
         ref_desc_pool_->FindMessageTypeByName(type);
     EXPECT_TRUE(desc != nullptr);
     EXPECT_TRUE(ref_desc != nullptr);
@@ -135,10 +133,10 @@
   std::unique_ptr<Server> server_;
   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
   std::unique_ptr<ProtoReflectionDescriptorDatabase> desc_db_;
-  std::unique_ptr<google::protobuf::DescriptorPool> desc_pool_;
+  std::unique_ptr<protobuf::DescriptorPool> desc_pool_;
   std::unordered_set<string> known_files_;
   std::unordered_set<string> known_types_;
-  const google::protobuf::DescriptorPool* ref_desc_pool_;
+  const protobuf::DescriptorPool* ref_desc_pool_;
   int port_;
   reflection::ProtoServerReflectionPlugin plugin_;
 };
diff --git a/test/cpp/grpclb/grpclb_api_test.cc b/test/cpp/grpclb/grpclb_api_test.cc
index bf77878..33de1ee 100644
--- a/test/cpp/grpclb/grpclb_api_test.cc
+++ b/test/cpp/grpclb/grpclb_api_test.cc
@@ -58,26 +58,24 @@
   grpc_grpclb_request_destroy(c_req);
 }
 
-TEST_F(GrpclbTest, ParseResponse) {
+TEST_F(GrpclbTest, ParseInitialResponse) {
   LoadBalanceResponse response;
   auto* initial_response = response.mutable_initial_response();
   auto* client_stats_report_interval =
       initial_response->mutable_client_stats_report_interval();
   client_stats_report_interval->set_seconds(123);
   client_stats_report_interval->set_nanos(456);
-
   const std::string encoded_response = response.SerializeAsString();
   gpr_slice encoded_slice =
       gpr_slice_from_copied_string(encoded_response.c_str());
-  grpc_grpclb_response* c_response = grpc_grpclb_response_parse(encoded_slice);
-  EXPECT_TRUE(c_response->has_initial_response);
-  EXPECT_FALSE(c_response->initial_response.has_load_balancer_delegate);
-  EXPECT_EQ(c_response->initial_response.client_stats_report_interval.seconds,
-            123);
-  EXPECT_EQ(c_response->initial_response.client_stats_report_interval.nanos,
-            456);
+
+  grpc_grpclb_initial_response* c_initial_response =
+      grpc_grpclb_initial_response_parse(encoded_slice);
+  EXPECT_FALSE(c_initial_response->has_load_balancer_delegate);
+  EXPECT_EQ(c_initial_response->client_stats_report_interval.seconds, 123);
+  EXPECT_EQ(c_initial_response->client_stats_report_interval.nanos, 456);
   gpr_slice_unref(encoded_slice);
-  grpc_grpclb_response_destroy(c_response);
+  grpc_grpclb_initial_response_destroy(c_initial_response);
 }
 
 TEST_F(GrpclbTest, ParseResponseServerList) {
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
new file mode 100644
index 0000000..b2fdce2
--- /dev/null
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -0,0 +1,689 @@
+/*
+ *
+ * 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 <cinttypes>
+#include <cstdarg>
+#include <cstdint>
+#include <cstring>
+#include <string>
+
+extern "C" {
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/time.h>
+
+#include "src/core/ext/client_config/client_channel.h"
+#include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/support/string.h"
+#include "src/core/lib/support/tmpfile.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/server.h"
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+}
+
+#include "src/proto/grpc/lb/v1/load_balancer.pb.h"
+
+#define NUM_BACKENDS 4
+
+// TODO(dgq): Other scenarios in need of testing:
+// - Send an empty serverlist update and verify that the client request blocks
+//   until a new serverlist with actual contents is available.
+// - Send identical serverlist update
+// - Test reception of invalid serverlist
+// - Test pinging
+// - Test against a non-LB server. That server should return UNIMPLEMENTED and
+//   the call should fail.
+// - Random LB server closing the stream unexpectedly.
+
+namespace grpc {
+namespace {
+
+typedef struct client_fixture {
+  grpc_channel *client;
+  char *server_uri;
+  grpc_completion_queue *cq;
+} client_fixture;
+
+typedef struct server_fixture {
+  grpc_server *server;
+  grpc_call *server_call;
+  grpc_completion_queue *cq;
+  char *servers_hostport;
+  int port;
+  gpr_thd_id tid;
+  int num_calls_serviced;
+} server_fixture;
+
+typedef struct test_fixture {
+  server_fixture lb_server;
+  server_fixture lb_backends[NUM_BACKENDS];
+  client_fixture client;
+  int lb_server_update_delay_ms;
+} test_fixture;
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+static gpr_slice build_response_payload_slice(
+    const char *host, int *ports, size_t nports,
+    int64_t expiration_interval_secs, int32_t expiration_interval_nanos) {
+  // server_list {
+  //   servers {
+  //     ip_address: "127.0.0.1"
+  //     port: ...
+  //     load_balance_token: "token..."
+  //   }
+  //   ...
+  // }
+  grpc::lb::v1::LoadBalanceResponse response;
+  auto *serverlist = response.mutable_server_list();
+
+  if (expiration_interval_secs > 0 || expiration_interval_nanos > 0) {
+    auto *expiration_interval = serverlist->mutable_expiration_interval();
+    if (expiration_interval_secs > 0) {
+      expiration_interval->set_seconds(expiration_interval_secs);
+    }
+    if (expiration_interval_nanos > 0) {
+      expiration_interval->set_nanos(expiration_interval_nanos);
+    }
+  }
+  for (size_t i = 0; i < nports; i++) {
+    auto *server = serverlist->add_servers();
+    server->set_ip_address(host);
+    server->set_port(ports[i]);
+    // The following long long int cast is meant to work around the
+    // disfunctional implementation of std::to_string in gcc 4.4, which doesn't
+    // have a version for int but does have one for long long int.
+    server->set_load_balance_token("token" +
+                                   std::to_string((long long int)ports[i]));
+  }
+
+  gpr_log(GPR_INFO, "generating response: %s",
+          response.ShortDebugString().c_str());
+
+  const gpr_slice response_slice =
+      gpr_slice_from_copied_string(response.SerializeAsString().c_str());
+  return response_slice;
+}
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5),
+                                    NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void sleep_ms(int delay_ms) {
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_millis(delay_ms, GPR_TIMESPAN)));
+}
+
+static void start_lb_server(server_fixture *sf, int *ports, size_t nports,
+                            int update_delay_ms) {
+  grpc_call *s;
+  cq_verifier *cqv = cq_verifier_create(sf->cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_call_error error;
+  int was_cancelled = 2;
+  grpc_byte_buffer *request_payload_recv;
+  grpc_byte_buffer *response_payload;
+
+  memset(ops, 0, sizeof(ops));
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  error = grpc_server_request_call(sf->server, &s, &call_details,
+                                   &request_metadata_recv, sf->cq, sf->cq,
+                                   tag(200));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  gpr_log(GPR_INFO, "LB Server[%s] up", sf->servers_hostport);
+  cq_expect_completion(cqv, tag(200), 1);
+  cq_verify(cqv);
+  gpr_log(GPR_INFO, "LB Server[%s] after tag 200", sf->servers_hostport);
+
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(201), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  gpr_log(GPR_INFO, "LB Server[%s] after tag 201", sf->servers_hostport);
+
+  // receive request for backends
+  op = ops;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message = &request_payload_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  cq_expect_completion(cqv, tag(202), 1);
+  cq_verify(cqv);
+  gpr_log(GPR_INFO, "LB Server[%s] after RECV_MSG", sf->servers_hostport);
+  // TODO(dgq): validate request.
+  grpc_byte_buffer_destroy(request_payload_recv);
+  gpr_slice response_payload_slice;
+  for (int i = 0; i < 2; i++) {
+    if (i == 0) {
+      // First half of the ports.
+      response_payload_slice =
+          build_response_payload_slice("127.0.0.1", ports, nports / 2, -1, -1);
+    } else {
+      // Second half of the ports.
+      sleep_ms(update_delay_ms);
+      response_payload_slice =
+          build_response_payload_slice("127.0.0.1", ports + (nports / 2),
+                                       (nports + 1) / 2 /* ceil */, -1, -1);
+    }
+
+    response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+    op = ops;
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->data.send_message = response_payload;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(203), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
+    cq_expect_completion(cqv, tag(203), 1);
+    cq_verify(cqv);
+    gpr_log(GPR_INFO, "LB Server[%s] after SEND_MESSAGE, iter %d",
+            sf->servers_hostport, i);
+
+    grpc_byte_buffer_destroy(response_payload);
+    gpr_slice_unref(response_payload_slice);
+  }
+  gpr_log(GPR_INFO, "LB Server[%s] shutting down", sf->servers_hostport);
+
+  op = ops;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_OK;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(204), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(201), 1);
+  cq_expect_completion(cqv, tag(204), 1);
+  cq_verify(cqv);
+  gpr_log(GPR_INFO, "LB Server[%s] after tag 204. All done. LB server out",
+          sf->servers_hostport);
+
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+}
+
+static void start_backend_server(server_fixture *sf) {
+  grpc_call *s;
+  cq_verifier *cqv;
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_call_error error;
+  int was_cancelled;
+  grpc_byte_buffer *request_payload_recv;
+  grpc_byte_buffer *response_payload;
+  grpc_event ev;
+
+  while (true) {
+    memset(ops, 0, sizeof(ops));
+    cqv = cq_verifier_create(sf->cq);
+    was_cancelled = 2;
+    grpc_metadata_array_init(&request_metadata_recv);
+    grpc_call_details_init(&call_details);
+
+    error = grpc_server_request_call(sf->server, &s, &call_details,
+                                     &request_metadata_recv, sf->cq, sf->cq,
+                                     tag(100));
+    GPR_ASSERT(GRPC_CALL_OK == error);
+    gpr_log(GPR_INFO, "Server[%s] up", sf->servers_hostport);
+    ev = grpc_completion_queue_next(sf->cq,
+                                    GRPC_TIMEOUT_SECONDS_TO_DEADLINE(60), NULL);
+    if (!ev.success) {
+      gpr_log(GPR_INFO, "Server[%s] being torn down", sf->servers_hostport);
+      cq_verifier_destroy(cqv);
+      grpc_metadata_array_destroy(&request_metadata_recv);
+      grpc_call_details_destroy(&call_details);
+      return;
+    }
+    GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+    gpr_log(GPR_INFO, "Server[%s] after tag 100", sf->servers_hostport);
+
+    op = ops;
+    op->op = GRPC_OP_SEND_INITIAL_METADATA;
+    op->data.send_initial_metadata.count = 0;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+    op->data.recv_close_on_server.cancelled = &was_cancelled;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(101), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
+    gpr_log(GPR_INFO, "Server[%s] after tag 101", sf->servers_hostport);
+
+    bool exit = false;
+    gpr_slice response_payload_slice =
+        gpr_slice_from_copied_string("hello you");
+    while (!exit) {
+      op = ops;
+      op->op = GRPC_OP_RECV_MESSAGE;
+      op->data.recv_message = &request_payload_recv;
+      op->flags = 0;
+      op->reserved = NULL;
+      op++;
+      error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+      GPR_ASSERT(GRPC_CALL_OK == error);
+      ev = grpc_completion_queue_next(
+          sf->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), NULL);
+      if (ev.type == GRPC_OP_COMPLETE && ev.success) {
+        GPR_ASSERT(ev.tag = tag(102));
+        if (request_payload_recv == NULL) {
+          exit = true;
+          gpr_log(GPR_INFO,
+                  "Server[%s] recv \"close\" from client, exiting. Call #%d",
+                  sf->servers_hostport, sf->num_calls_serviced);
+        }
+      } else {
+        gpr_log(GPR_INFO, "Server[%s] forced to shutdown. Call #%d",
+                sf->servers_hostport, sf->num_calls_serviced);
+        exit = true;
+      }
+      gpr_log(GPR_INFO, "Server[%s] after tag 102. Call #%d",
+              sf->servers_hostport, sf->num_calls_serviced);
+
+      if (!exit) {
+        response_payload =
+            grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+        op = ops;
+        op->op = GRPC_OP_SEND_MESSAGE;
+        op->data.send_message = response_payload;
+        op->flags = 0;
+        op->reserved = NULL;
+        op++;
+        error =
+            grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
+        GPR_ASSERT(GRPC_CALL_OK == error);
+        ev = grpc_completion_queue_next(
+            sf->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), NULL);
+        if (ev.type == GRPC_OP_COMPLETE && ev.success) {
+          GPR_ASSERT(ev.tag = tag(103));
+        } else {
+          gpr_log(GPR_INFO, "Server[%s] forced to shutdown. Call #%d",
+                  sf->servers_hostport, sf->num_calls_serviced);
+          exit = true;
+        }
+        gpr_log(GPR_INFO, "Server[%s] after tag 103. Call #%d",
+                sf->servers_hostport, sf->num_calls_serviced);
+        grpc_byte_buffer_destroy(response_payload);
+      }
+
+      grpc_byte_buffer_destroy(request_payload_recv);
+    }
+    ++sf->num_calls_serviced;
+
+    gpr_log(GPR_INFO, "Server[%s] OUT OF THE LOOP", sf->servers_hostport);
+    gpr_slice_unref(response_payload_slice);
+
+    op = ops;
+    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+    op->data.send_status_from_server.trailing_metadata_count = 0;
+    op->data.send_status_from_server.status = GRPC_STATUS_OK;
+    op->data.send_status_from_server.status_details = "Backend server out a-ok";
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
+
+    cq_expect_completion(cqv, tag(101), 1);
+    cq_expect_completion(cqv, tag(104), 1);
+    cq_verify(cqv);
+    gpr_log(GPR_INFO, "Server[%s] DONE. After servicing %d calls",
+            sf->servers_hostport, sf->num_calls_serviced);
+
+    grpc_call_destroy(s);
+    cq_verifier_destroy(cqv);
+    grpc_metadata_array_destroy(&request_metadata_recv);
+    grpc_call_details_destroy(&call_details);
+  }
+}
+
+static void perform_request(client_fixture *cf) {
+  grpc_call *c;
+  cq_verifier *cqv = cq_verifier_create(cf->cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_status_code status;
+  grpc_call_error error;
+  char *details = NULL;
+  size_t details_capacity = 0;
+  grpc_byte_buffer *request_payload;
+  grpc_byte_buffer *response_payload_recv;
+  int i;
+
+  memset(ops, 0, sizeof(ops));
+  gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
+
+  c = grpc_channel_create_call(cf->client, NULL, GRPC_PROPAGATE_DEFAULTS,
+                               cf->cq, "/foo", "foo.test.google.fr:1234",
+                               GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1000), NULL);
+  gpr_log(GPR_INFO, "Call 0x%" PRIxPTR " created", (intptr_t)c);
+  GPR_ASSERT(c);
+  char *peer;
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  for (i = 0; i < 4; i++) {
+    request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+
+    op = ops;
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->data.send_message = request_payload;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->data.recv_message = &response_payload_recv;
+    op->flags = 0;
+    op->reserved = NULL;
+    op++;
+    error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL);
+    GPR_ASSERT(GRPC_CALL_OK == error);
+
+    peer = grpc_call_get_peer(c);
+    cq_expect_completion(cqv, tag(2), 1);
+    cq_verify(cqv);
+    gpr_free(peer);
+
+    grpc_byte_buffer_destroy(request_payload);
+    grpc_byte_buffer_destroy(response_payload_recv);
+  }
+
+  gpr_slice_unref(request_payload_slice);
+
+  op = ops;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  cq_expect_completion(cqv, tag(1), 1);
+  cq_expect_completion(cqv, tag(3), 1);
+  cq_verify(cqv);
+  peer = grpc_call_get_peer(c);
+  gpr_log(GPR_INFO, "Client DONE WITH SERVER %s ", peer);
+  gpr_free(peer);
+
+  grpc_call_destroy(c);
+
+  cq_verify_empty_timeout(cqv, 1);
+  cq_verifier_destroy(cqv);
+
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  gpr_free(details);
+}
+
+static void setup_client(const char *server_hostport, client_fixture *cf) {
+  cf->cq = grpc_completion_queue_create(NULL);
+  cf->server_uri = gpr_strdup(server_hostport);
+  cf->client = grpc_insecure_channel_create(cf->server_uri, NULL, NULL);
+}
+
+static void teardown_client(client_fixture *cf) {
+  grpc_completion_queue_shutdown(cf->cq);
+  drain_cq(cf->cq);
+  grpc_completion_queue_destroy(cf->cq);
+  cf->cq = NULL;
+  grpc_channel_destroy(cf->client);
+  cf->client = NULL;
+  gpr_free(cf->server_uri);
+}
+
+static void setup_server(const char *host, server_fixture *sf) {
+  int assigned_port;
+
+  sf->cq = grpc_completion_queue_create(NULL);
+  const char *colon_idx = strchr(host, ':');
+  if (colon_idx) {
+    const char *port_str = colon_idx + 1;
+    sf->port = atoi(port_str);
+    sf->servers_hostport = gpr_strdup(host);
+  } else {
+    sf->port = grpc_pick_unused_port_or_die();
+    gpr_join_host_port(&sf->servers_hostport, host, sf->port);
+  }
+
+  sf->server = grpc_server_create(NULL, NULL);
+  grpc_server_register_completion_queue(sf->server, sf->cq, NULL);
+  GPR_ASSERT((assigned_port = grpc_server_add_insecure_http2_port(
+                  sf->server, sf->servers_hostport)) > 0);
+  GPR_ASSERT(sf->port == assigned_port);
+  grpc_server_start(sf->server);
+}
+
+static void teardown_server(server_fixture *sf) {
+  if (!sf->server) return;
+
+  gpr_log(GPR_INFO, "Server[%s] shutting down", sf->servers_hostport);
+  grpc_server_shutdown_and_notify(sf->server, sf->cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 sf->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(sf->server);
+  gpr_thd_join(sf->tid);
+
+  sf->server = NULL;
+  grpc_completion_queue_shutdown(sf->cq);
+  drain_cq(sf->cq);
+  grpc_completion_queue_destroy(sf->cq);
+
+  gpr_log(GPR_INFO, "Server[%s] bye bye", sf->servers_hostport);
+  gpr_free(sf->servers_hostport);
+}
+
+static void fork_backend_server(void *arg) {
+  server_fixture *sf = static_cast<server_fixture *>(arg);
+  start_backend_server(sf);
+}
+
+static void fork_lb_server(void *arg) {
+  test_fixture *tf = static_cast<test_fixture *>(arg);
+  int ports[NUM_BACKENDS];
+  for (int i = 0; i < NUM_BACKENDS; i++) {
+    ports[i] = tf->lb_backends[i].port;
+  }
+  start_lb_server(&tf->lb_server, ports, NUM_BACKENDS,
+                  tf->lb_server_update_delay_ms);
+}
+
+static void setup_test_fixture(test_fixture *tf,
+                               int lb_server_update_delay_ms) {
+  tf->lb_server_update_delay_ms = lb_server_update_delay_ms;
+
+  gpr_thd_options options = gpr_thd_options_default();
+  gpr_thd_options_set_joinable(&options);
+
+  for (int i = 0; i < NUM_BACKENDS; ++i) {
+    setup_server("127.0.0.1", &tf->lb_backends[i]);
+    gpr_thd_new(&tf->lb_backends[i].tid, fork_backend_server,
+                &tf->lb_backends[i], &options);
+  }
+
+  setup_server("127.0.0.1", &tf->lb_server);
+  gpr_thd_new(&tf->lb_server.tid, fork_lb_server, &tf->lb_server, &options);
+
+  char *server_uri;
+  gpr_asprintf(&server_uri, "ipv4:%s?lb_policy=grpclb&lb_enabled=1",
+               tf->lb_server.servers_hostport);
+  setup_client(server_uri, &tf->client);
+  gpr_free(server_uri);
+}
+
+static void teardown_test_fixture(test_fixture *tf) {
+  teardown_client(&tf->client);
+  for (int i = 0; i < NUM_BACKENDS; ++i) {
+    teardown_server(&tf->lb_backends[i]);
+  }
+  teardown_server(&tf->lb_server);
+}
+
+// The LB server will send two updates: batch 1 and batch 2. Each batch
+// contains
+// two addresses, both of a valid and running backend server. Batch 1 is
+// readily
+// available and provided as soon as the client establishes the streaming
+// call.
+// Batch 2 is sent after a delay of \a lb_server_update_delay_ms
+// milliseconds.
+static test_fixture test_update(int lb_server_update_delay_ms) {
+  gpr_log(GPR_INFO, "start %s(%d)", __func__, lb_server_update_delay_ms);
+  test_fixture tf;
+  memset(&tf, 0, sizeof(tf));
+  setup_test_fixture(&tf, lb_server_update_delay_ms);
+  perform_request(
+      &tf.client);  // "consumes" 1st backend server of 1st serverlist
+  perform_request(
+      &tf.client);  // "consumes" 2nd backend server of 1st serverlist
+
+  perform_request(
+      &tf.client);  // "consumes" 1st backend server of 2nd serverlist
+  perform_request(
+      &tf.client);  // "consumes" 2nd backend server of 2nd serverlist
+
+  teardown_test_fixture(&tf);
+  gpr_log(GPR_INFO, "end %s(%d)", __func__, lb_server_update_delay_ms);
+  return tf;
+}
+
+}  // namespace
+}  // namespace grpc
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+
+  grpc::test_fixture tf_result;
+  // Clients take a bit over one second to complete a call (the last part of the
+  // call sleeps for 1 second while verifying the client's completion queue is
+  // empty). Therefore:
+  //
+  // If the LB server waits 800ms before sending an update, it will arrive
+  // before the first client request is done, skipping the second server from
+  // batch 1 altogether: the 2nd client request will go to the 1st server of
+  // batch 2 (ie, the third one out of the four total servers).
+  tf_result = grpc::test_update(800);
+  GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced == 1);
+  GPR_ASSERT(tf_result.lb_backends[1].num_calls_serviced == 0);
+  GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced == 2);
+  GPR_ASSERT(tf_result.lb_backends[3].num_calls_serviced == 1);
+
+  // If the LB server waits 1500ms, the update arrives after having picked the
+  // 2nd server from batch 1 but before the next pick for the first server of
+  // batch 2. All server are used.
+  tf_result = grpc::test_update(1500);
+  GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced == 1);
+  GPR_ASSERT(tf_result.lb_backends[1].num_calls_serviced == 1);
+  GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced == 1);
+  GPR_ASSERT(tf_result.lb_backends[3].num_calls_serviced == 1);
+
+  // If the LB server waits > 2000ms, the update arrives after the first two
+  // request are done and the third pick is performed, which returns, in RR
+  // fashion, the 1st server of the 1st update. Therefore, the second server of
+  // batch 1 is hit at least one, whereas the first server of batch 2 is never
+  // hit.
+  tf_result = grpc::test_update(2500);
+  GPR_ASSERT(tf_result.lb_backends[0].num_calls_serviced >= 1);
+  GPR_ASSERT(tf_result.lb_backends[1].num_calls_serviced > 0);
+  GPR_ASSERT(tf_result.lb_backends[2].num_calls_serviced > 0);
+  GPR_ASSERT(tf_result.lb_backends[3].num_calls_serviced == 0);
+
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc
index ebef000..e5878bb 100644
--- a/test/cpp/interop/interop_server.cc
+++ b/test/cpp/interop/interop_server.cc
@@ -31,7 +31,6 @@
  *
  */
 
-#include <signal.h>
 #include <unistd.h>
 
 #include <fstream>
@@ -78,8 +77,6 @@
 using grpc::testing::TestService;
 using grpc::Status;
 
-static bool got_sigint = false;
-
 const char kEchoInitialMetadataKey[] = "x-grpc-test-echo-initial";
 const char kEchoTrailingBinMetadataKey[] = "x-grpc-test-echo-trailing-bin";
 const char kEchoUserAgentKey[] = "x-grpc-test-echo-useragent";
@@ -311,7 +308,9 @@
   }
 };
 
-void RunServer() {
+void grpc::testing::interop::RunServer(
+    std::shared_ptr<ServerCredentials> creds) {
+  GPR_ASSERT(FLAGS_port != 0);
   std::ostringstream server_address;
   server_address << "0.0.0.0:" << FLAGS_port;
   TestServiceImpl service;
@@ -321,24 +320,10 @@
 
   ServerBuilder builder;
   builder.RegisterService(&service);
-  std::shared_ptr<ServerCredentials> creds =
-      grpc::testing::CreateInteropServerCredentials();
   builder.AddListeningPort(server_address.str(), creds);
   std::unique_ptr<Server> server(builder.BuildAndStart());
   gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str());
-  while (!got_sigint) {
+  while (!g_got_sigint) {
     sleep(5);
   }
 }
-
-static void sigint_handler(int x) { got_sigint = true; }
-
-int main(int argc, char** argv) {
-  grpc::testing::InitTest(&argc, &argv, true);
-  signal(SIGINT, sigint_handler);
-
-  GPR_ASSERT(FLAGS_port != 0);
-  RunServer();
-
-  return 0;
-}
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/test/cpp/interop/interop_server_bootstrap.cc
similarity index 70%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to test/cpp/interop/interop_server_bootstrap.cc
index df2324c..424f7ca 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/test/cpp/interop/interop_server_bootstrap.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,24 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#include <signal.h>
+#include <unistd.h>
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#include "test/cpp/interop/server_helper.h"
+#include "test/cpp/util/test_config.h"
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+bool grpc::testing::interop::g_got_sigint = false;
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+static void sigint_handler(int x) {
+  grpc::testing::interop::g_got_sigint = true;
+}
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+int main(int argc, char** argv) {
+  grpc::testing::InitTest(&argc, &argv, true);
+  signal(SIGINT, sigint_handler);
+
+  grpc::testing::interop::RunServer(
+      grpc::testing::CreateInteropServerCredentials());
+
+  return 0;
+}
diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h
index a1da14a..fc4ea8b3e 100644
--- a/test/cpp/interop/server_helper.h
+++ b/test/cpp/interop/server_helper.h
@@ -60,6 +60,12 @@
   const ::grpc::ServerContext& context_;
 };
 
+namespace interop {
+
+extern bool g_got_sigint;
+void RunServer(std::shared_ptr<ServerCredentials> creds);
+
+}  // namespace interop
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 4045e13..fada4ba 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -169,6 +169,7 @@
   // Must call AwaitThreadsCompletion before destructor to avoid a race
   // between destructor and invocation of virtual ThreadFunc
   void AwaitThreadsCompletion() {
+    gpr_atm_rel_store(&thread_pool_done_, static_cast<gpr_atm>(true));
     DestroyMultithreading();
     std::unique_lock<std::mutex> g(thread_completion_mu_);
     while (threads_remaining_ != 0) {
@@ -178,8 +179,10 @@
 
  protected:
   bool closed_loop_;
+  gpr_atm thread_pool_done_;
 
   void StartThreads(size_t num_threads) {
+    gpr_atm_rel_store(&thread_pool_done_, static_cast<gpr_atm>(false));
     threads_remaining_ = num_threads;
     for (size_t i = 0; i < num_threads; i++) {
       threads_.emplace_back(new Thread(this, i));
@@ -241,18 +244,9 @@
   class Thread {
    public:
     Thread(Client* client, size_t idx)
-        : done_(false),
-          client_(client),
-          idx_(idx),
-          impl_(&Thread::ThreadFunc, this) {}
+        : client_(client), idx_(idx), impl_(&Thread::ThreadFunc, this) {}
 
-    ~Thread() {
-      {
-        std::lock_guard<std::mutex> g(mu_);
-        done_ = true;
-      }
-      impl_.join();
-    }
+    ~Thread() { impl_.join(); }
 
     void BeginSwap(Histogram* n) {
       std::lock_guard<std::mutex> g(mu_);
@@ -282,9 +276,9 @@
         }
         if (!thread_still_ok) {
           gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
-          done_ = true;
         }
-        if (done_) {
+        if (!thread_still_ok ||
+            static_cast<bool>(gpr_atm_acq_load(&client_->thread_pool_done_))) {
           client_->CompleteThread();
           return;
         }
@@ -292,7 +286,6 @@
     }
 
     std::mutex mu_;
-    bool done_;
     Histogram histogram_;
     Client* client_;
     const size_t idx_;
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 25c7823..8062424 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -79,10 +79,29 @@
   virtual ~SynchronousClient(){};
 
  protected:
-  void WaitToIssue(int thread_idx) {
+  // WaitToIssue returns false if we realize that we need to break out
+  bool WaitToIssue(int thread_idx) {
     if (!closed_loop_) {
-      gpr_sleep_until(NextIssueTime(thread_idx));
+      const gpr_timespec next_issue_time = NextIssueTime(thread_idx);
+      // Avoid sleeping for too long continuously because we might
+      // need to terminate before then. This is an issue since
+      // exponential distribution can occasionally produce bad outliers
+      while (true) {
+        const gpr_timespec one_sec_delay =
+            gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                         gpr_time_from_seconds(1, GPR_TIMESPAN));
+        if (gpr_time_cmp(next_issue_time, one_sec_delay) <= 0) {
+          gpr_sleep_until(next_issue_time);
+          return true;
+        } else {
+          gpr_sleep_until(one_sec_delay);
+          if (gpr_atm_acq_load(&thread_pool_done_) != static_cast<gpr_atm>(0)) {
+            return false;
+          }
+        }
+      }
     }
+    return true;
   }
 
   size_t num_threads_;
@@ -101,7 +120,9 @@
   ~SynchronousUnaryClient() {}
 
   bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) GRPC_OVERRIDE {
-    WaitToIssue(thread_idx);
+    if (!WaitToIssue(thread_idx)) {
+      return true;
+    }
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
     double start = UsageTimer::Now();
     GPR_TIMER_SCOPE("SynchronousUnaryClient::ThreadFunc", 0);
@@ -144,7 +165,9 @@
   }
 
   bool ThreadFunc(HistogramEntry* entry, size_t thread_idx) GRPC_OVERRIDE {
-    WaitToIssue(thread_idx);
+    if (!WaitToIssue(thread_idx)) {
+      return true;
+    }
     GPR_TIMER_SCOPE("SynchronousStreamingClient::ThreadFunc", 0);
     double start = UsageTimer::Now();
     if (stream_[thread_idx]->Write(request_) &&
diff --git a/test/cpp/qps/limit_cores.cc b/test/cpp/qps/limit_cores.cc
index 59ed369..b5c2225 100644
--- a/test/cpp/qps/limit_cores.cc
+++ b/test/cpp/qps/limit_cores.cc
@@ -68,9 +68,9 @@
       cores_set++;
     }
   }
-  GPR_ASSERT(sched_setaffinity(0, size, cpup) == 0);
+  bool affinity_set = (sched_setaffinity(0, size, cpup) == 0);
   CPU_FREE(cpup);
-  return cores_set;
+  return affinity_set ? cores_set : num_cores;
 }
 
 }  // namespace testing
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index dea8746..082b4bc 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -108,14 +108,14 @@
           auto request_unary =
               std::bind(request_unary_function, &async_service_, _1, _2, _3,
                         srv_cqs_[j].get(), srv_cqs_[j].get(), _4);
-          contexts_.push_front(
+          contexts_.emplace_back(
               new ServerRpcContextUnaryImpl(request_unary, process_rpc_bound));
         }
         if (request_streaming_function) {
           auto request_streaming =
               std::bind(request_streaming_function, &async_service_, _1, _2,
                         srv_cqs_[j].get(), srv_cqs_[j].get(), _3);
-          contexts_.push_front(new ServerRpcContextStreamingImpl(
+          contexts_.emplace_back(new ServerRpcContextStreamingImpl(
               request_streaming, process_rpc_bound));
         }
       }
@@ -146,10 +146,6 @@
       while ((*cq)->Next(&got_tag, &ok))
         ;
     }
-    while (!contexts_.empty()) {
-      delete contexts_.front();
-      contexts_.pop_front();
-    }
   }
 
  private:
@@ -336,7 +332,7 @@
   std::unique_ptr<grpc::Server> server_;
   std::vector<std::unique_ptr<grpc::ServerCompletionQueue>> srv_cqs_;
   ServiceType async_service_;
-  std::forward_list<ServerRpcContext *> contexts_;
+  std::vector<std::unique_ptr<ServerRpcContext>> contexts_;
 
   struct PerThreadShutdownState {
     mutable std::mutex mutex;
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/test/cpp/util/cli_credentials.cc
similarity index 62%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to test/cpp/util/cli_credentials.cc
index df2324c..8de9393 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/test/cpp/util/cli_credentials.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,33 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#include "test/cpp/util/cli_credentials.h"
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#include <gflags/gflags.h>
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
+DEFINE_bool(use_auth, false, "Whether to create default google credentials.");
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+namespace grpc {
+namespace testing {
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+std::shared_ptr<grpc::ChannelCredentials> CliCredentials::GetCredentials()
+    const {
+  if (!FLAGS_enable_ssl) {
+    return grpc::InsecureChannelCredentials();
+  } else {
+    if (FLAGS_use_auth) {
+      return grpc::GoogleDefaultCredentials();
+    } else {
+      return grpc::SslCredentials(grpc::SslCredentialsOptions());
+    }
+  }
+}
+
+const grpc::string CliCredentials::GetCredentialUsage() const {
+  return "    --enable_ssl             ; Set whether to use tls\n"
+         "    --use_auth               ; Set whether to create default google"
+         " credentials\n";
+}
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/test/cpp/util/cli_credentials.h
similarity index 70%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to test/cpp/util/cli_credentials.h
index df2324c..581b77a 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/test/cpp/util/cli_credentials.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,23 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#ifndef GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
+#define GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#include <grpc++/security/credentials.h>
+#include <grpc++/support/config.h>
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+namespace grpc {
+namespace testing {
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+class CliCredentials {
+ public:
+  virtual ~CliCredentials() {}
+  virtual std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const;
+  virtual const grpc::string GetCredentialUsage() const;
+};
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_CLI_CREDENTIALS_H
diff --git a/test/cpp/util/config_grpc_cli.h b/test/cpp/util/config_grpc_cli.h
new file mode 100644
index 0000000..ea8231a
--- /dev/null
+++ b/test/cpp/util/config_grpc_cli.h
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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_UTIL_CONFIG_GRPC_CLI_H
+#define GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
+
+#include <grpc++/impl/codegen/config_protobuf.h>
+
+#ifndef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY
+#include <google/protobuf/dynamic_message.h>
+#define GRPC_CUSTOM_DYNAMICMESSAGEFACTORY \
+  ::google::protobuf::DynamicMessageFactory
+#endif
+
+#ifndef GRPC_CUSTOM_DESCRIPTORPOOLDATABASE
+#include <google/protobuf/descriptor.h>
+#define GRPC_CUSTOM_DESCRIPTORPOOLDATABASE \
+  ::google::protobuf::DescriptorPoolDatabase
+#define GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE \
+  ::google::protobuf::MergedDescriptorDatabase
+#endif
+
+#ifndef GRPC_CUSTOM_TEXTFORMAT
+#include <google/protobuf/text_format.h>
+#define GRPC_CUSTOM_TEXTFORMAT ::google::protobuf::TextFormat
+#endif
+
+#ifndef GRPC_CUSTOM_DISKSOURCETREE
+#include <google/protobuf/compiler/importer.h>
+#define GRPC_CUSTOM_DISKSOURCETREE ::google::protobuf::compiler::DiskSourceTree
+#define GRPC_CUSTOM_IMPORTER ::google::protobuf::compiler::Importer
+#define GRPC_CUSTOM_MULTIFILEERRORCOLLECTOR \
+  ::google::protobuf::compiler::MultiFileErrorCollector
+#endif
+
+namespace grpc {
+namespace protobuf {
+
+typedef GRPC_CUSTOM_DYNAMICMESSAGEFACTORY DynamicMessageFactory;
+
+typedef GRPC_CUSTOM_DESCRIPTORPOOLDATABASE DescriptorPoolDatabase;
+typedef GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE MergedDescriptorDatabase;
+
+typedef GRPC_CUSTOM_TEXTFORMAT TextFormat;
+
+namespace compiler {
+typedef GRPC_CUSTOM_DISKSOURCETREE DiskSourceTree;
+typedef GRPC_CUSTOM_IMPORTER Importer;
+typedef GRPC_CUSTOM_MULTIFILEERRORCOLLECTOR MultiFileErrorCollector;
+}  // namespace importer
+
+}  // namespace protobuf
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_CONFIG_GRPC_CLI_H
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
index c52e48b..fe24860 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -33,27 +33,34 @@
 
 /*
   A command line tool to talk to a grpc server.
+  Run `grpc_cli help` command to see its usage information.
+
   Example of talking to grpc interop server:
-  grpc_cli call localhost:50051 UnaryCall src/proto/grpc/testing/test.proto \
-    "response_size:10"  --enable_ssl=false
+  grpc_cli call localhost:50051 UnaryCall "response_size:10" \
+      --protofiles=src/proto/grpc/testing/test.proto --enable_ssl=false
 
   Options:
-    1. --proto_path, if your proto file is not under current working directory,
+    1. --protofiles, use this flag to provide proto files if the server does
+       does not have the reflection service.
+    2. --proto_path, if your proto file is not under current working directory,
        use this flag to provide a search root. It should work similar to the
-       counterpart in protoc.
-    2. --metadata specifies metadata to be sent to the server, such as:
+       counterpart in protoc. This option is valid only when protofiles is
+       provided.
+    3. --metadata specifies metadata to be sent to the server, such as:
        --metadata="MyHeaderKey1:Value1:MyHeaderKey2:Value2"
-    3. --enable_ssl, whether to use tls.
-    4. --use_auth, if set to true, attach a GoogleDefaultCredentials to the call
-    3. --input_binary_file, a file containing the serialized request. The file
-       can be generated by calling something like:
+    4. --enable_ssl, whether to use tls.
+    5. --use_auth, if set to true, attach a GoogleDefaultCredentials to the call
+    6. --infile, input filename (defaults to stdin)
+    7. --outfile, output filename (defaults to stdout)
+    8. --binary_input, use the serialized request as input. The serialized
+       request can be generated by calling something like:
        protoc --proto_path=src/proto/grpc/testing/ \
          --encode=grpc.testing.SimpleRequest \
          src/proto/grpc/testing/messages.proto \
          < input.txt > input.bin
        If this is used and no proto file is provided in the argument list, the
        method string has to be exact in the form of /package.service/method.
-    4. --output_binary_file, a file to write binary format response into, it can
+    9. --binary_output, use binary format response as output, it can
        be later decoded using protoc:
        protoc --proto_path=src/proto/grpc/testing/ \
        --decode=grpc.testing.SimpleResponse \
@@ -62,165 +69,33 @@
 */
 
 #include <fstream>
+#include <functional>
 #include <iostream>
-#include <sstream>
 
 #include <gflags/gflags.h>
-#include <grpc++/channel.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/security/credentials.h>
-#include <grpc++/support/string_ref.h>
-#include <grpc/grpc.h>
-
-#include "test/cpp/util/cli_call.h"
-#include "test/cpp/util/proto_file_parser.h"
-#include "test/cpp/util/string_ref_helper.h"
+#include <grpc++/support/config.h>
+#include "test/cpp/util/cli_credentials.h"
+#include "test/cpp/util/grpc_tool.h"
 #include "test/cpp/util/test_config.h"
 
-DEFINE_bool(enable_ssl, true, "Whether to use ssl/tls.");
-DEFINE_bool(use_auth, false, "Whether to create default google credentials.");
-DEFINE_string(input_binary_file, "",
-              "Path to input file containing serialized request.");
-DEFINE_string(output_binary_file, "",
-              "Path to output file to write serialized response.");
-DEFINE_string(metadata, "",
-              "Metadata to send to server, in the form of key1:val1:key2:val2");
-DEFINE_string(proto_path, ".", "Path to look for the proto file.");
+DEFINE_string(outfile, "", "Output file (default is stdout)");
 
-void ParseMetadataFlag(
-    std::multimap<grpc::string, grpc::string>* client_metadata) {
-  if (FLAGS_metadata.empty()) {
-    return;
+static bool SimplePrint(const grpc::string& outfile,
+                        const grpc::string& output) {
+  if (outfile.empty()) {
+    std::cout << output;
+  } else {
+    std::ofstream output_file(outfile, std::ios::trunc | std::ios::binary);
+    output_file << output;
+    output_file.close();
   }
-  std::vector<grpc::string> fields;
-  const char* delim = ":";
-  size_t cur, next = -1;
-  do {
-    cur = next + 1;
-    next = FLAGS_metadata.find_first_of(delim, cur);
-    fields.push_back(FLAGS_metadata.substr(cur, next - cur));
-  } while (next != grpc::string::npos);
-  if (fields.size() % 2) {
-    std::cout << "Failed to parse metadata flag" << std::endl;
-    exit(1);
-  }
-  for (size_t i = 0; i < fields.size(); i += 2) {
-    client_metadata->insert(
-        std::pair<grpc::string, grpc::string>(fields[i], fields[i + 1]));
-  }
-}
-
-template <typename T>
-void PrintMetadata(const T& m, const grpc::string& message) {
-  if (m.empty()) {
-    return;
-  }
-  std::cout << message << std::endl;
-  grpc::string pair;
-  for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
-    pair.clear();
-    pair.append(iter->first.data(), iter->first.size());
-    pair.append(" : ");
-    pair.append(iter->second.data(), iter->second.size());
-    std::cout << pair << std::endl;
-  }
+  return true;
 }
 
 int main(int argc, char** argv) {
   grpc::testing::InitTest(&argc, &argv, true);
 
-  if (argc < 4 || argc == 5 || grpc::string(argv[1]) != "call") {
-    std::cout << "Usage: grpc_cli call server_host:port method_name "
-              << "[proto file] [text format request] [<options>]" << std::endl;
-  }
-
-  grpc::string file_name;
-  grpc::string request_text;
-  grpc::string server_address(argv[2]);
-  grpc::string method_name(argv[3]);
-  std::unique_ptr<grpc::testing::ProtoFileParser> parser;
-  grpc::string serialized_request_proto;
-
-  if (argc == 6) {
-    file_name = argv[4];
-    // TODO(yangg) read from stdin as well?
-    request_text = argv[5];
-  }
-
-  if (request_text.empty() && FLAGS_input_binary_file.empty()) {
-    std::cout << "Missing input. Use text format input or "
-              << "--input_binary_file for serialized request" << std::endl;
-    return 1;
-  } else if (!request_text.empty()) {
-    parser.reset(new grpc::testing::ProtoFileParser(FLAGS_proto_path, file_name,
-                                                    method_name));
-    method_name = parser->GetFullMethodName();
-    if (parser->HasError()) {
-      return 1;
-    }
-  }
-
-  if (parser) {
-    serialized_request_proto =
-        parser->GetSerializedProto(request_text, true /* is_request */);
-    if (parser->HasError()) {
-      return 1;
-    }
-  } else if (!FLAGS_input_binary_file.empty()) {
-    std::ifstream input_file(FLAGS_input_binary_file,
-                             std::ios::in | std::ios::binary);
-    std::stringstream input_stream;
-    input_stream << input_file.rdbuf();
-    serialized_request_proto = input_stream.str();
-  }
-  std::cout << "connecting to " << server_address << std::endl;
-
-  std::shared_ptr<grpc::ChannelCredentials> creds;
-  if (!FLAGS_enable_ssl) {
-    creds = grpc::InsecureChannelCredentials();
-  } else {
-    if (FLAGS_use_auth) {
-      creds = grpc::GoogleDefaultCredentials();
-    } else {
-      creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
-    }
-  }
-  std::shared_ptr<grpc::Channel> channel =
-      grpc::CreateChannel(server_address, creds);
-
-  grpc::string serialized_response_proto;
-  std::multimap<grpc::string, grpc::string> client_metadata;
-  std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
-      server_trailing_metadata;
-  ParseMetadataFlag(&client_metadata);
-  PrintMetadata(client_metadata, "Sending client initial metadata:");
-  grpc::Status s = grpc::testing::CliCall::Call(
-      channel, method_name, serialized_request_proto,
-      &serialized_response_proto, client_metadata, &server_initial_metadata,
-      &server_trailing_metadata);
-  PrintMetadata(server_initial_metadata,
-                "Received initial metadata from server:");
-  PrintMetadata(server_trailing_metadata,
-                "Received trailing metadata from server:");
-  if (s.ok()) {
-    std::cout << "Rpc succeeded with OK status" << std::endl;
-    if (parser) {
-      grpc::string response_text = parser->GetTextFormat(
-          serialized_response_proto, false /* is_request */);
-      if (parser->HasError()) {
-        return 1;
-      }
-      std::cout << "Response: \n " << response_text << std::endl;
-    }
-    if (!FLAGS_output_binary_file.empty()) {
-      std::ofstream output_file(FLAGS_output_binary_file,
-                                std::ios::trunc | std::ios::binary);
-      output_file << serialized_response_proto;
-    }
-  } else {
-    std::cout << "Rpc failed with status code " << s.error_code()
-              << " error message " << s.error_message() << std::endl;
-  }
-
-  return 0;
+  return grpc::testing::GrpcToolMainLib(
+      argc, (const char**)argv, grpc::testing::CliCredentials(),
+      std::bind(SimplePrint, FLAGS_outfile, std::placeholders::_1));
 }
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
new file mode 100644
index 0000000..f06053c
--- /dev/null
+++ b/test/cpp/util/grpc_tool.cc
@@ -0,0 +1,365 @@
+/*
+ *
+ * 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 "test/cpp/util/grpc_tool.h"
+
+#include <unistd.h>
+#include <fstream>
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include <gflags/gflags.h>
+#include <grpc++/channel.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/grpc++.h>
+#include <grpc++/security/credentials.h>
+#include <grpc++/support/string_ref.h>
+#include <grpc/grpc.h>
+
+#include "test/cpp/util/cli_call.h"
+#include "test/cpp/util/proto_file_parser.h"
+#include "test/cpp/util/proto_reflection_descriptor_database.h"
+#include "test/cpp/util/test_config.h"
+
+DEFINE_bool(remotedb, true, "Use server types to parse and format messages");
+DEFINE_string(metadata, "",
+              "Metadata to send to server, in the form of key1:val1:key2:val2");
+DEFINE_string(proto_path, ".", "Path to look for the proto file.");
+DEFINE_string(proto_file, "", "Name of the proto file.");
+DEFINE_bool(binary_input, false, "Input in binary format");
+DEFINE_bool(binary_output, false, "Output in binary format");
+DEFINE_string(infile, "", "Input file (default is stdin)");
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class GrpcTool {
+ public:
+  explicit GrpcTool();
+  virtual ~GrpcTool() {}
+
+  bool Help(int argc, const char** argv, CliCredentials cred,
+            GrpcToolOutputCallback callback);
+  bool CallMethod(int argc, const char** argv, CliCredentials cred,
+                  GrpcToolOutputCallback callback);
+  // TODO(zyc): implement the following methods
+  // bool ListServices(int argc, const char** argv, GrpcToolOutputCallback
+  // callback);
+  // bool PrintType(int argc, const char** argv, GrpcToolOutputCallback
+  // 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);
+
+  void SetPrintCommandMode(int exit_status) {
+    print_command_usage_ = true;
+    usage_exit_status_ = exit_status;
+  }
+
+ private:
+  void CommandUsage(const grpc::string& usage) const;
+  bool print_command_usage_;
+  int usage_exit_status_;
+  const grpc::string cred_usage_;
+};
+
+template <typename T>
+std::function<bool(GrpcTool*, int, const char**, const CliCredentials,
+                   GrpcToolOutputCallback)>
+BindWith5Args(T&& func) {
+  return std::bind(std::forward<T>(func), std::placeholders::_1,
+                   std::placeholders::_2, std::placeholders::_3,
+                   std::placeholders::_4, std::placeholders::_5);
+}
+
+template <typename T>
+size_t ArraySize(T& a) {
+  return ((sizeof(a) / sizeof(*(a))) /
+          static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
+void ParseMetadataFlag(
+    std::multimap<grpc::string, grpc::string>* client_metadata) {
+  if (FLAGS_metadata.empty()) {
+    return;
+  }
+  std::vector<grpc::string> fields;
+  const char* delim = ":";
+  size_t cur, next = -1;
+  do {
+    cur = next + 1;
+    next = FLAGS_metadata.find_first_of(delim, cur);
+    fields.push_back(FLAGS_metadata.substr(cur, next - cur));
+  } while (next != grpc::string::npos);
+  if (fields.size() % 2) {
+    fprintf(stderr, "Failed to parse metadata flag.\n");
+    exit(1);
+  }
+  for (size_t i = 0; i < fields.size(); i += 2) {
+    client_metadata->insert(
+        std::pair<grpc::string, grpc::string>(fields[i], fields[i + 1]));
+  }
+}
+
+template <typename T>
+void PrintMetadata(const T& m, const grpc::string& message) {
+  if (m.empty()) {
+    return;
+  }
+  fprintf(stderr, "%s\n", message.c_str());
+  grpc::string pair;
+  for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) {
+    pair.clear();
+    pair.append(iter->first.data(), iter->first.size());
+    pair.append(" : ");
+    pair.append(iter->second.data(), iter->second.size());
+    fprintf(stderr, "%s\n", pair.c_str());
+  }
+}
+
+struct Command {
+  const char* command;
+  std::function<bool(GrpcTool*, int, const char**, const CliCredentials,
+                     GrpcToolOutputCallback)>
+      function;
+  int min_args;
+  int max_args;
+};
+
+const Command ops[] = {
+    {"help", BindWith5Args(&GrpcTool::Help), 0, INT_MAX},
+    // {"ls", BindWith5Args(&GrpcTool::ListServices), 1, 3},
+    // {"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},
+};
+
+void Usage(const grpc::string& msg) {
+  fprintf(
+      stderr,
+      "%s\n"
+      // "  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 help ...       ; Print this message, or per-command usage\n"
+      "\n",
+      msg.c_str());
+
+  exit(1);
+}
+
+const Command* FindCommand(const grpc::string& name) {
+  for (int i = 0; i < (int)ArraySize(ops); i++) {
+    if (name == ops[i].command) {
+      return &ops[i];
+    }
+  }
+  return NULL;
+}
+}  // namespace
+
+int GrpcToolMainLib(int argc, const char** argv, const CliCredentials cred,
+                    GrpcToolOutputCallback callback) {
+  if (argc < 2) {
+    Usage("No command specified");
+  }
+
+  grpc::string command = argv[1];
+  argc -= 2;
+  argv += 2;
+
+  const Command* cmd = FindCommand(command);
+  if (cmd != NULL) {
+    GrpcTool grpc_tool;
+    if (argc < cmd->min_args || argc > cmd->max_args) {
+      // Force the command to print its usage message
+      fprintf(stderr, "\nWrong number of arguments for %s\n", command.c_str());
+      grpc_tool.SetPrintCommandMode(1);
+      return cmd->function(&grpc_tool, -1, NULL, cred, callback);
+    }
+    const bool ok = cmd->function(&grpc_tool, argc, argv, cred, callback);
+    return ok ? 0 : 1;
+  } else {
+    Usage("Invalid command '" + grpc::string(command.c_str()) + "'");
+  }
+  return 1;
+}
+
+GrpcTool::GrpcTool() : print_command_usage_(false), usage_exit_status_(0) {}
+
+void GrpcTool::CommandUsage(const grpc::string& usage) const {
+  if (print_command_usage_) {
+    fprintf(stderr, "\n%s%s\n", usage.c_str(),
+            (usage.empty() || usage[usage.size() - 1] != '\n') ? "\n" : "");
+    exit(usage_exit_status_);
+  }
+}
+
+bool GrpcTool::Help(int argc, const char** argv, const CliCredentials cred,
+                    GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Print help\n"
+      "  grpc_cli help [subcommand]\n");
+
+  if (argc == 0) {
+    Usage("");
+  } else {
+    const Command* cmd = FindCommand(argv[0]);
+    if (cmd == NULL) {
+      Usage("Unknown command '" + grpc::string(argv[0]) + "'");
+    }
+    SetPrintCommandMode(0);
+    cmd->function(this, -1, NULL, cred, callback);
+  }
+  return true;
+}
+
+bool GrpcTool::CallMethod(int argc, const char** argv,
+                          const CliCredentials cred,
+                          GrpcToolOutputCallback callback) {
+  CommandUsage(
+      "Call method\n"
+      "  grpc_cli call <address> <service>[.<method>] <request>\n"
+      "    <address>                ; host:port\n"
+      "    <service>                ; Exported service name\n"
+      "    <method>                 ; Method name\n"
+      "    <request>                ; Text protobuffer (overrides infile)\n"
+      "    --proto_file             ; Comma separated proto files used as a"
+      " fallback when parsing request/response\n"
+      "    --proto_path             ; The search path of proto files, valid"
+      " only when --proto_file is given\n"
+      "    --metadata               ; The metadata to be sent to the server\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 request_text;
+  grpc::string server_address(argv[0]);
+  grpc::string method_name(argv[1]);
+  std::unique_ptr<grpc::testing::ProtoFileParser> parser;
+  grpc::string serialized_request_proto;
+
+  if (argc == 3) {
+    request_text = argv[2];
+    if (!FLAGS_infile.empty()) {
+      fprintf(stderr, "warning: request 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();
+    }
+    request_text = input_stream.str();
+  }
+
+  std::shared_ptr<grpc::Channel> channel =
+      grpc::CreateChannel(server_address, cred.GetCredentials());
+  if (!FLAGS_binary_input || !FLAGS_binary_output) {
+    parser.reset(
+        new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr,
+                                           FLAGS_proto_path, FLAGS_proto_file));
+    if (parser->HasError()) {
+      return false;
+    }
+  }
+
+  if (FLAGS_binary_input) {
+    serialized_request_proto = request_text;
+  } else {
+    serialized_request_proto = parser->GetSerializedProtoFromMethod(
+        method_name, request_text, true /* is_request */);
+    if (parser->HasError()) {
+      return false;
+    }
+  }
+  fprintf(stderr, "connecting to %s\n", server_address.c_str());
+
+  grpc::string serialized_response_proto;
+  std::multimap<grpc::string, grpc::string> client_metadata;
+  std::multimap<grpc::string_ref, grpc::string_ref> server_initial_metadata,
+      server_trailing_metadata;
+  ParseMetadataFlag(&client_metadata);
+  PrintMetadata(client_metadata, "Sending client initial metadata:");
+  grpc::Status status = grpc::testing::CliCall::Call(
+      channel, parser->GetFormatedMethodName(method_name),
+      serialized_request_proto, &serialized_response_proto, client_metadata,
+      &server_initial_metadata, &server_trailing_metadata);
+  PrintMetadata(server_initial_metadata,
+                "Received initial metadata from server:");
+  PrintMetadata(server_trailing_metadata,
+                "Received trailing metadata from server:");
+  if (status.ok()) {
+    fprintf(stderr, "Rpc succeeded with OK status\n");
+    if (FLAGS_binary_output) {
+      output_ss << serialized_response_proto;
+    } else {
+      grpc::string response_text = parser->GetTextFormatFromMethod(
+          method_name, serialized_response_proto, false /* is_request */);
+      if (parser->HasError()) {
+        return false;
+      }
+      output_ss << "Response: \n " << response_text << std::endl;
+    }
+  } else {
+    fprintf(stderr, "Rpc failed with status code %d, error message: %s\n",
+            status.error_code(), status.error_message().c_str());
+  }
+
+  return callback(output_ss.str());
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/core/ext/transport/chttp2/transport/timeout_encoding.h b/test/cpp/util/grpc_tool.h
similarity index 70%
copy from src/core/ext/transport/chttp2/transport/timeout_encoding.h
copy to test/cpp/util/grpc_tool.h
index df2324c..3da8693 100644
--- a/src/core/ext/transport/chttp2/transport/timeout_encoding.h
+++ b/test/cpp/util/grpc_tool.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,24 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
-#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H
+#ifndef GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
+#define GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
 
-#include <grpc/support/time.h>
-#include "src/core/lib/support/string.h"
+#include <functional>
 
-#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
+#include <grpc++/support/config.h>
 
-/* Encode/decode timeouts to the GRPC over HTTP2 format;
-   encoding may round up arbitrarily */
-void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);
-int grpc_chttp2_decode_timeout(const char *buffer, gpr_timespec *timeout);
+#include "test/cpp/util/cli_credentials.h"
 
-#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_TIMEOUT_ENCODING_H */
+namespace grpc {
+namespace testing {
+
+typedef std::function<bool(const grpc::string &)> GrpcToolOutputCallback;
+
+int GrpcToolMainLib(int argc, const char **argv, CliCredentials cred,
+                    GrpcToolOutputCallback callback);
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_GRPC_TOOL_H
diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc
new file mode 100644
index 0000000..b96afaf
--- /dev/null
+++ b/test/cpp/util/grpc_tool_test.cc
@@ -0,0 +1,227 @@
+/*
+ *
+ * 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 "test/cpp/util/grpc_tool.h"
+
+#include <sstream>
+
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/ext/proto_server_reflection_plugin.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "src/proto/grpc/testing/echo.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/util/cli_credentials.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+using grpc::testing::EchoRequest;
+using grpc::testing::EchoResponse;
+
+namespace grpc {
+namespace testing {
+namespace {
+
+class TestCliCredentials GRPC_FINAL : public grpc::testing::CliCredentials {
+ public:
+  std::shared_ptr<grpc::ChannelCredentials> GetCredentials() const
+      GRPC_OVERRIDE {
+    return InsecureChannelCredentials();
+  }
+  const grpc::string GetCredentialUsage() const GRPC_OVERRIDE { return ""; }
+};
+
+}  // namespame
+
+class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
+ public:
+  Status Echo(ServerContext* context, const EchoRequest* request,
+              EchoResponse* response) GRPC_OVERRIDE {
+    if (!context->client_metadata().empty()) {
+      for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
+               iter = context->client_metadata().begin();
+           iter != context->client_metadata().end(); ++iter) {
+        context->AddInitialMetadata(ToString(iter->first),
+                                    ToString(iter->second));
+      }
+    }
+    context->AddTrailingMetadata("trailing_key", "trailing_value");
+    response->set_message(request->message());
+    return Status::OK;
+  }
+};
+
+class GrpcToolTest : public ::testing::Test {
+ protected:
+  GrpcToolTest() {}
+
+  // SetUpServer cannot be used with EXPECT_EXIT. grpc_pick_unused_port_or_die()
+  // uses atexit() to free chosen ports, and it will spawn a new thread in
+  // resolve_address_posix.c:192 at exit time.
+  const grpc::string SetUpServer() {
+    std::ostringstream server_address;
+    int port = grpc_pick_unused_port_or_die();
+    server_address << "localhost:" << port;
+    // Setup server
+    ServerBuilder builder;
+    builder.AddListeningPort(server_address.str(), InsecureServerCredentials());
+    builder.RegisterService(&service_);
+    server_ = builder.BuildAndStart();
+    return server_address.str();
+  }
+
+  void ShutdownServer() { server_->Shutdown(); }
+
+  std::unique_ptr<Server> server_;
+  TestServiceImpl service_;
+  reflection::ProtoServerReflectionPlugin plugin_;
+};
+
+static bool PrintStream(std::stringstream* ss, const grpc::string& output) {
+  (*ss) << output << std::endl;
+  return true;
+}
+
+template <typename T>
+static size_t ArraySize(T& a) {
+  return ((sizeof(a) / sizeof(*(a))) /
+          static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))));
+}
+
+#define USAGE_REGEX "(  grpc_cli .+\n){2,10}"
+
+TEST_F(GrpcToolTest, NoCommand) {
+  // Test input "grpc_cli"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli"};
+  // Exit with 1, print usage instruction in stderr
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), "No command specified\n" USAGE_REGEX);
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, InvalidCommand) {
+  // Test input "grpc_cli"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "abc"};
+  // Exit with 1, print usage instruction in stderr
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), "Invalid command 'abc'\n" USAGE_REGEX);
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, HelpCommand) {
+  // Test input "grpc_cli help"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "help"};
+  // Exit with 1, print usage instruction in stderr
+  EXPECT_EXIT(GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+                              std::bind(PrintStream, &output_stream,
+                                        std::placeholders::_1)),
+              ::testing::ExitedWithCode(1), USAGE_REGEX);
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, CallCommand) {
+  // Test input "grpc_cli call Echo"
+  std::stringstream output_stream;
+
+  const grpc::string server_address = SetUpServer();
+  const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
+                        "message: 'Hello'"};
+
+  EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
+                                   std::bind(PrintStream, &output_stream,
+                                             std::placeholders::_1)));
+  // Expected output: "message: \"Hello\""
+  EXPECT_TRUE(NULL !=
+              strstr(output_stream.str().c_str(), "message: \"Hello\""));
+  ShutdownServer();
+}
+
+TEST_F(GrpcToolTest, TooFewArguments) {
+  // Test input "grpc_cli call localhost:<port> Echo "message: 'Hello'"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "call", "Echo"};
+
+  // Exit with 1
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+TEST_F(GrpcToolTest, TooManyArguments) {
+  // Test input "grpc_cli call localhost:<port> Echo Echo "message: 'Hello'"
+  std::stringstream output_stream;
+  const char* argv[] = {"grpc_cli", "call", "localhost:10000",
+                        "Echo",     "Echo", "message: 'Hello'"};
+
+  // Exit with 1
+  EXPECT_EXIT(
+      GrpcToolMainLib(
+          ArraySize(argv), argv, TestCliCredentials(),
+          std::bind(PrintStream, &output_stream, std::placeholders::_1)),
+      ::testing::ExitedWithCode(1), ".*Wrong number of arguments for call.*");
+  // No output
+  EXPECT_TRUE(0 == output_stream.tellp());
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/util/proto_file_parser.cc b/test/cpp/util/proto_file_parser.cc
index 25aec32..0c88c24 100644
--- a/test/cpp/util/proto_file_parser.cc
+++ b/test/cpp/util/proto_file_parser.cc
@@ -37,7 +37,6 @@
 #include <iostream>
 #include <sstream>
 
-#include <google/protobuf/text_format.h>
 #include <grpc++/support/config.h>
 
 namespace grpc {
@@ -56,8 +55,7 @@
 }
 }  // namespace
 
-class ErrorPrinter
-    : public google::protobuf::compiler::MultiFileErrorCollector {
+class ErrorPrinter : public protobuf::compiler::MultiFileErrorCollector {
  public:
   explicit ErrorPrinter(ProtoFileParser* parser) : parser_(parser) {}
 
@@ -71,7 +69,7 @@
 
   void AddWarning(const grpc::string& filename, int line, int column,
                   const grpc::string& message) GRPC_OVERRIDE {
-    std::cout << "warning " << filename << " " << line << " " << column << " "
+    std::cerr << "warning " << filename << " " << line << " " << column << " "
               << message << std::endl;
   }
 
@@ -79,25 +77,71 @@
   ProtoFileParser* parser_;  // not owned
 };
 
-ProtoFileParser::ProtoFileParser(const grpc::string& proto_path,
-                                 const grpc::string& file_name,
-                                 const grpc::string& method)
+ProtoFileParser::ProtoFileParser(std::shared_ptr<grpc::Channel> channel,
+                                 const grpc::string& proto_path,
+                                 const grpc::string& protofiles)
     : has_error_(false) {
-  source_tree_.MapPath("", proto_path);
-  error_printer_.reset(new ErrorPrinter(this));
-  importer_.reset(new google::protobuf::compiler::Importer(
-      &source_tree_, error_printer_.get()));
-  const auto* file_desc = importer_->Import(file_name);
-  if (!file_desc) {
-    LogError("");
+  std::vector<std::string> service_list;
+  if (channel) {
+    reflection_db_.reset(new grpc::ProtoReflectionDescriptorDatabase(channel));
+    reflection_db_->GetServices(&service_list);
+  }
+
+  if (!protofiles.empty()) {
+    source_tree_.MapPath("", proto_path);
+    error_printer_.reset(new ErrorPrinter(this));
+    importer_.reset(
+        new protobuf::compiler::Importer(&source_tree_, error_printer_.get()));
+
+    grpc::string file_name;
+    std::stringstream ss(protofiles);
+    while (std::getline(ss, file_name, ',')) {
+      const auto* file_desc = importer_->Import(file_name);
+      if (file_desc) {
+        for (int i = 0; i < file_desc->service_count(); i++) {
+          service_desc_list_.push_back(file_desc->service(i));
+        }
+      } else {
+        std::cerr << file_name << " not found" << std::endl;
+      }
+    }
+
+    file_db_.reset(new protobuf::DescriptorPoolDatabase(*importer_->pool()));
+  }
+
+  if (!reflection_db_ && !file_db_) {
+    LogError("No available proto database");
     return;
   }
-  dynamic_factory_.reset(
-      new google::protobuf::DynamicMessageFactory(importer_->pool()));
 
-  const google::protobuf::MethodDescriptor* method_descriptor = nullptr;
-  for (int i = 0; !method_descriptor && i < file_desc->service_count(); i++) {
-    const auto* service_desc = file_desc->service(i);
+  if (!reflection_db_) {
+    desc_db_ = std::move(file_db_);
+  } else if (!file_db_) {
+    desc_db_ = std::move(reflection_db_);
+  } else {
+    desc_db_.reset(new protobuf::MergedDescriptorDatabase(reflection_db_.get(),
+                                                          file_db_.get()));
+  }
+
+  desc_pool_.reset(new protobuf::DescriptorPool(desc_db_.get()));
+  dynamic_factory_.reset(new protobuf::DynamicMessageFactory(desc_pool_.get()));
+
+  for (auto it = service_list.begin(); it != service_list.end(); it++) {
+    if (const protobuf::ServiceDescriptor* service_desc =
+            desc_pool_->FindServiceByName(*it)) {
+      service_desc_list_.push_back(service_desc);
+    }
+  }
+}
+
+ProtoFileParser::~ProtoFileParser() {}
+
+grpc::string ProtoFileParser::GetFullMethodName(const grpc::string& method) {
+  has_error_ = false;
+  const protobuf::MethodDescriptor* method_descriptor = nullptr;
+  for (auto it = service_desc_list_.begin(); it != service_desc_list_.end();
+       it++) {
+    const auto* service_desc = *it;
     for (int j = 0; j < service_desc->method_count(); j++) {
       const auto* method_desc = service_desc->method(j);
       if (MethodNameMatch(method_desc->full_name(), method)) {
@@ -115,35 +159,87 @@
     LogError("Method name not found");
   }
   if (has_error_) {
-    return;
+    return "";
   }
-  full_method_name_ = method_descriptor->full_name();
-  size_t last_dot = full_method_name_.find_last_of('.');
-  if (last_dot != grpc::string::npos) {
-    full_method_name_[last_dot] = '/';
-  }
-  full_method_name_.insert(full_method_name_.begin(), '/');
 
-  request_prototype_.reset(
-      dynamic_factory_->GetPrototype(method_descriptor->input_type())->New());
-  response_prototype_.reset(
-      dynamic_factory_->GetPrototype(method_descriptor->output_type())->New());
+  return method_descriptor->full_name();
 }
 
-ProtoFileParser::~ProtoFileParser() {}
+grpc::string ProtoFileParser::GetFormatedMethodName(
+    const grpc::string& method) {
+  has_error_ = false;
+  grpc::string formated_method_name = GetFullMethodName(method);
+  if (has_error_) {
+    return "";
+  }
+  size_t last_dot = formated_method_name.find_last_of('.');
+  if (last_dot != grpc::string::npos) {
+    formated_method_name[last_dot] = '/';
+  }
+  formated_method_name.insert(formated_method_name.begin(), '/');
+  return formated_method_name;
+}
 
-grpc::string ProtoFileParser::GetSerializedProto(
-    const grpc::string& text_format_proto, bool is_request) {
+grpc::string ProtoFileParser::GetMessageTypeFromMethod(
+    const grpc::string& method, bool is_request) {
+  has_error_ = false;
+  grpc::string full_method_name = GetFullMethodName(method);
+  if (has_error_) {
+    return "";
+  }
+  const protobuf::MethodDescriptor* method_desc =
+      desc_pool_->FindMethodByName(full_method_name);
+  if (!method_desc) {
+    LogError("Method not found");
+    return "";
+  }
+
+  return is_request ? method_desc->input_type()->full_name()
+                    : method_desc->output_type()->full_name();
+}
+
+grpc::string ProtoFileParser::GetSerializedProtoFromMethod(
+    const grpc::string& method, const grpc::string& text_format_proto,
+    bool is_request) {
+  has_error_ = false;
+  grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
+  if (has_error_) {
+    return "";
+  }
+  return GetSerializedProtoFromMessageType(message_type_name,
+                                           text_format_proto);
+}
+
+grpc::string ProtoFileParser::GetTextFormatFromMethod(
+    const grpc::string& method, const grpc::string& serialized_proto,
+    bool is_request) {
+  has_error_ = false;
+  grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
+  if (has_error_) {
+    return "";
+  }
+  return GetTextFormatFromMessageType(message_type_name, serialized_proto);
+}
+
+grpc::string ProtoFileParser::GetSerializedProtoFromMessageType(
+    const grpc::string& message_type_name,
+    const grpc::string& text_format_proto) {
+  has_error_ = false;
   grpc::string serialized;
-  grpc::protobuf::Message* msg =
-      is_request ? request_prototype_.get() : response_prototype_.get();
-  bool ok =
-      google::protobuf::TextFormat::ParseFromString(text_format_proto, msg);
+  const protobuf::Descriptor* desc =
+      desc_pool_->FindMessageTypeByName(message_type_name);
+  if (!desc) {
+    LogError("Message type not found");
+    return "";
+  }
+  std::unique_ptr<grpc::protobuf::Message> msg(
+      dynamic_factory_->GetPrototype(desc)->New());
+  bool ok = protobuf::TextFormat::ParseFromString(text_format_proto, msg.get());
   if (!ok) {
     LogError("Failed to parse text format to proto.");
     return "";
   }
-  ok = request_prototype_->SerializeToString(&serialized);
+  ok = msg->SerializeToString(&serialized);
   if (!ok) {
     LogError("Failed to serialize proto.");
     return "";
@@ -151,16 +247,24 @@
   return serialized;
 }
 
-grpc::string ProtoFileParser::GetTextFormat(
-    const grpc::string& serialized_proto, bool is_request) {
-  grpc::protobuf::Message* msg =
-      is_request ? request_prototype_.get() : response_prototype_.get();
+grpc::string ProtoFileParser::GetTextFormatFromMessageType(
+    const grpc::string& message_type_name,
+    const grpc::string& serialized_proto) {
+  has_error_ = false;
+  const protobuf::Descriptor* desc =
+      desc_pool_->FindMessageTypeByName(message_type_name);
+  if (!desc) {
+    LogError("Message type not found");
+    return "";
+  }
+  std::unique_ptr<grpc::protobuf::Message> msg(
+      dynamic_factory_->GetPrototype(desc)->New());
   if (!msg->ParseFromString(serialized_proto)) {
     LogError("Failed to deserialize proto.");
     return "";
   }
   grpc::string text_format;
-  if (!google::protobuf::TextFormat::PrintToString(*msg, &text_format)) {
+  if (!protobuf::TextFormat::PrintToString(*msg.get(), &text_format)) {
     LogError("Failed to print proto message to text format");
     return "";
   }
@@ -169,7 +273,7 @@
 
 void ProtoFileParser::LogError(const grpc::string& error_msg) {
   if (!error_msg.empty()) {
-    std::cout << error_msg << std::endl;
+    std::cerr << error_msg << std::endl;
   }
   has_error_ = true;
 }
diff --git a/test/cpp/util/proto_file_parser.h b/test/cpp/util/proto_file_parser.h
index 46cdd66..eda3991 100644
--- a/test/cpp/util/proto_file_parser.h
+++ b/test/cpp/util/proto_file_parser.h
@@ -36,10 +36,10 @@
 
 #include <memory>
 
-#include <google/protobuf/compiler/importer.h>
-#include <google/protobuf/dynamic_message.h>
+#include <grpc++/channel.h>
 
-#include "src/compiler/config.h"
+#include "test/cpp/util/config_grpc_cli.h"
+#include "test/cpp/util/proto_reflection_descriptor_database.h"
 
 namespace grpc {
 namespace testing {
@@ -48,35 +48,63 @@
 // Find method and associated request/response types.
 class ProtoFileParser {
  public:
-  // The given proto file_name will be searched in a source tree rooted from
-  // proto_path. The method could be a partial string such as Service.Method or
-  // even just Method. It will log an error if there is ambiguity.
-  ProtoFileParser(const grpc::string& proto_path, const grpc::string& file_name,
-                  const grpc::string& method);
+  // The parser will search proto files using the server reflection service
+  // provided on the given channel. The given protofiles in a source tree rooted
+  // from proto_path will also be searched.
+  ProtoFileParser(std::shared_ptr<grpc::Channel> channel,
+                  const grpc::string& proto_path,
+                  const grpc::string& protofiles);
+
   ~ProtoFileParser();
 
-  grpc::string GetFullMethodName() const { return full_method_name_; }
+  // The input method name in the following four functions could be a partial
+  // string such as Service.Method or even just Method. It will log an error if
+  // there is ambiguity.
+  // Full method name is in the form of Service.Method, it's good to be used in
+  // descriptor database queries.
+  grpc::string GetFullMethodName(const grpc::string& method);
 
-  grpc::string GetSerializedProto(const grpc::string& text_format_proto,
-                                  bool is_request);
+  // Formated method name is in the form of /Service/Method, it's good to be
+  // used as the argument of Stub::Call()
+  grpc::string GetFormatedMethodName(const grpc::string& method);
 
-  grpc::string GetTextFormat(const grpc::string& serialized_proto,
-                             bool is_request);
+  grpc::string GetSerializedProtoFromMethod(
+      const grpc::string& method, const grpc::string& text_format_proto,
+      bool is_request);
+
+  grpc::string GetTextFormatFromMethod(const grpc::string& method,
+                                       const grpc::string& serialized_proto,
+                                       bool is_request);
+
+  grpc::string GetSerializedProtoFromMessageType(
+      const grpc::string& message_type_name,
+      const grpc::string& text_format_proto);
+
+  grpc::string GetTextFormatFromMessageType(
+      const grpc::string& message_type_name,
+      const grpc::string& serialized_proto);
 
   bool HasError() const { return has_error_; }
 
   void LogError(const grpc::string& error_msg);
 
  private:
+  grpc::string GetMessageTypeFromMethod(const grpc::string& method,
+                                        bool is_request);
+
   bool has_error_;
   grpc::string request_text_;
-  grpc::string full_method_name_;
-  google::protobuf::compiler::DiskSourceTree source_tree_;
+  protobuf::compiler::DiskSourceTree source_tree_;
   std::unique_ptr<ErrorPrinter> error_printer_;
-  std::unique_ptr<google::protobuf::compiler::Importer> importer_;
-  std::unique_ptr<google::protobuf::DynamicMessageFactory> dynamic_factory_;
+  std::unique_ptr<protobuf::compiler::Importer> importer_;
+  std::unique_ptr<grpc::ProtoReflectionDescriptorDatabase> reflection_db_;
+  std::unique_ptr<protobuf::DescriptorPoolDatabase> file_db_;
+  std::unique_ptr<protobuf::DescriptorDatabase> desc_db_;
+  std::unique_ptr<protobuf::DescriptorPool> desc_pool_;
+  std::unique_ptr<protobuf::DynamicMessageFactory> dynamic_factory_;
   std::unique_ptr<grpc::protobuf::Message> request_prototype_;
   std::unique_ptr<grpc::protobuf::Message> response_prototype_;
+  std::vector<const protobuf::ServiceDescriptor*> service_desc_list_;
 };
 
 }  // namespace testing
diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc
index 25b720a..f0d14c6 100644
--- a/test/cpp/util/proto_reflection_descriptor_database.cc
+++ b/test/cpp/util/proto_reflection_descriptor_database.cc
@@ -53,10 +53,20 @@
     std::shared_ptr<grpc::Channel> channel)
     : stub_(ServerReflection::NewStub(channel)) {}
 
-ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {}
+ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {
+  if (stream_) {
+    stream_->WritesDone();
+    Status status = stream_->Finish();
+    if (!status.ok()) {
+      gpr_log(GPR_INFO,
+              "ServerReflectionInfo rpc failed. Error code: %d, details: %s",
+              (int)status.error_code(), status.error_message().c_str());
+    }
+  }
+}
 
 bool ProtoReflectionDescriptorDatabase::FindFileByName(
-    const string& filename, google::protobuf::FileDescriptorProto* output) {
+    const string& filename, protobuf::FileDescriptorProto* output) {
   if (cached_db_.FindFileByName(filename, output)) {
     return true;
   }
@@ -101,7 +111,7 @@
 }
 
 bool ProtoReflectionDescriptorDatabase::FindFileContainingSymbol(
-    const string& symbol_name, google::protobuf::FileDescriptorProto* output) {
+    const string& symbol_name, protobuf::FileDescriptorProto* output) {
   if (cached_db_.FindFileContainingSymbol(symbol_name, output)) {
     return true;
   }
@@ -148,7 +158,7 @@
 
 bool ProtoReflectionDescriptorDatabase::FindFileContainingExtension(
     const string& containing_type, int field_number,
-    google::protobuf::FileDescriptorProto* output) {
+    protobuf::FileDescriptorProto* output) {
   if (cached_db_.FindFileContainingExtension(containing_type, field_number,
                                              output)) {
     return true;
@@ -276,10 +286,10 @@
   return false;
 }
 
-const google::protobuf::FileDescriptorProto
+const protobuf::FileDescriptorProto
 ProtoReflectionDescriptorDatabase::ParseFileDescriptorProtoResponse(
     const std::string& byte_fd_proto) {
-  google::protobuf::FileDescriptorProto file_desc_proto;
+  protobuf::FileDescriptorProto file_desc_proto;
   file_desc_proto.ParseFromString(byte_fd_proto);
   return file_desc_proto;
 }
@@ -287,7 +297,7 @@
 void ProtoReflectionDescriptorDatabase::AddFileFromResponse(
     const grpc::reflection::v1alpha::FileDescriptorResponse& response) {
   for (int i = 0; i < response.file_descriptor_proto_size(); ++i) {
-    const google::protobuf::FileDescriptorProto file_proto =
+    const protobuf::FileDescriptorProto file_proto =
         ParseFileDescriptorProtoResponse(response.file_descriptor_proto(i));
     if (known_files_.find(file_proto.name()) == known_files_.end()) {
       known_files_.insert(file_proto.name());
diff --git a/test/cpp/util/proto_reflection_descriptor_database.h b/test/cpp/util/proto_reflection_descriptor_database.h
index 99c0067..eb7cf49 100644
--- a/test/cpp/util/proto_reflection_descriptor_database.h
+++ b/test/cpp/util/proto_reflection_descriptor_database.h
@@ -38,19 +38,19 @@
 #include <unordered_set>
 #include <vector>
 
-#include <google/protobuf/descriptor.h>
-#include <google/protobuf/descriptor.pb.h>
-#include <google/protobuf/descriptor_database.h>
+// GRPC_NO_GENERATED_CODE indicates generated pb files should not be used
+#ifdef GRPC_NO_GENERATED_CODE
+#include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h"
+#else
 #include <grpc++/ext/reflection.grpc.pb.h>
+#endif  // GRPC_NO_GENERATED_CODE
 #include <grpc++/grpc++.h>
-
 namespace grpc {
 
 // ProtoReflectionDescriptorDatabase takes a stub of ServerReflection and
 // provides the methods defined by DescriptorDatabase interfaces. It can be used
 // to feed a DescriptorPool instance.
-class ProtoReflectionDescriptorDatabase
-    : public google::protobuf::DescriptorDatabase {
+class ProtoReflectionDescriptorDatabase : public protobuf::DescriptorDatabase {
  public:
   explicit ProtoReflectionDescriptorDatabase(
       std::unique_ptr<reflection::v1alpha::ServerReflection::Stub> stub);
@@ -65,14 +65,13 @@
   // Find a file by file name.  Fills in in *output and returns true if found.
   // Otherwise, returns false, leaving the contents of *output undefined.
   bool FindFileByName(const string& filename,
-                      google::protobuf::FileDescriptorProto* output)
-      GRPC_OVERRIDE;
+                      protobuf::FileDescriptorProto* output) GRPC_OVERRIDE;
 
   // Find the file that declares the given fully-qualified symbol name.
   // If found, fills in *output and returns true, otherwise returns false
   // and leaves *output undefined.
   bool FindFileContainingSymbol(const string& symbol_name,
-                                google::protobuf::FileDescriptorProto* output)
+                                protobuf::FileDescriptorProto* output)
       GRPC_OVERRIDE;
 
   // Find the file which defines an extension extending the given message type
@@ -81,7 +80,7 @@
   // must be a fully-qualified type name.
   bool FindFileContainingExtension(
       const string& containing_type, int field_number,
-      google::protobuf::FileDescriptorProto* output) GRPC_OVERRIDE;
+      protobuf::FileDescriptorProto* output) GRPC_OVERRIDE;
 
   // Finds the tag numbers used by all known extensions of
   // extendee_type, and appends them to output in an undefined
@@ -102,7 +101,7 @@
       grpc::reflection::v1alpha::ServerReflectionResponse>
       ClientStream;
 
-  const google::protobuf::FileDescriptorProto ParseFileDescriptorProtoResponse(
+  const protobuf::FileDescriptorProto ParseFileDescriptorProtoResponse(
       const std::string& byte_fd_proto);
 
   void AddFileFromResponse(
@@ -123,7 +122,7 @@
   std::unordered_map<string, std::vector<int>> cached_extension_numbers_;
   std::mutex stream_mutex_;
 
-  google::protobuf::SimpleDescriptorDatabase cached_db_;
+  protobuf::SimpleDescriptorDatabase cached_db_;
 };
 
 }  // namespace grpc
diff --git a/test/cpp/util/slice_test.cc b/test/cpp/util/slice_test.cc
index de7ff03..45799ae 100644
--- a/test/cpp/util/slice_test.cc
+++ b/test/cpp/util/slice_test.cc
@@ -68,6 +68,16 @@
   CheckSlice(empty_slice, "");
 }
 
+TEST_F(SliceTest, Cslice) {
+  gpr_slice s = gpr_slice_from_copied_string(kContent);
+  Slice spp(s, Slice::STEAL_REF);
+  CheckSlice(spp, kContent);
+  gpr_slice c_slice = spp.c_slice();
+  EXPECT_EQ(GPR_SLICE_START_PTR(s), GPR_SLICE_START_PTR(c_slice));
+  EXPECT_EQ(GPR_SLICE_END_PTR(s), GPR_SLICE_END_PTR(c_slice));
+  gpr_slice_unref(c_slice);
+}
+
 }  // namespace
 }  // namespace grpc
 
diff --git a/third_party/thrift b/third_party/thrift
new file mode 160000
index 0000000..bcad917
--- /dev/null
+++ b/third_party/thrift
@@ -0,0 +1 @@
+Subproject commit bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c
diff --git a/tools/cmake/gRPCConfig.cmake.in b/tools/cmake/gRPCConfig.cmake.in
new file mode 100644
index 0000000..48f0674
--- /dev/null
+++ b/tools/cmake/gRPCConfig.cmake.in
@@ -0,0 +1,7 @@
+# Depend packages

+@_gRPC_FIND_ZLIB@

+@_gRPC_FIND_PROTOBUF@

+@_gRPC_FIND_SSL@

+

+# Targets

+include(${CMAKE_CURRENT_LIST_DIR}/gRPCTargets.cmake)

diff --git a/tools/cmake/gRPCConfigVersion.cmake.in b/tools/cmake/gRPCConfigVersion.cmake.in
new file mode 100644
index 0000000..f3c19fd
--- /dev/null
+++ b/tools/cmake/gRPCConfigVersion.cmake.in
@@ -0,0 +1,11 @@
+set(PACKAGE_VERSION "@PACKAGE_VERSION@")

+

+# Check whether the requested PACKAGE_FIND_VERSION is compatible

+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")

+    set(PACKAGE_VERSION_COMPATIBLE FALSE)

+else()

+    set(PACKAGE_VERSION_COMPATIBLE TRUE)

+    if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")

+        set(PACKAGE_VERSION_EXACT TRUE)

+    endif()

+endif()

diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index faa8386..859adcb 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -50,8 +50,8 @@
     'host',
     'grpc-message',
     'grpc-status',
-    'census-bin',
-    'census-binary-bin',
+    'grpc-tracing-bin',
+    'grpc-census-bin',
     '',
     ('grpc-status', '0'),
     ('grpc-status', '1'),
@@ -108,7 +108,8 @@
     ('if-range', ''),
     ('if-unmodified-since', ''),
     ('last-modified', ''),
-    ('load-reporting', ''),
+    ('load-reporting-initial', ''),
+    ('load-reporting-trailing', ''),
     ('link', ''),
     ('location', ''),
     ('max-forwards', ''),
diff --git a/tools/distrib/check_include_guards.py b/tools/distrib/check_include_guards.py
index 56b2924..2831281 100755
--- a/tools/distrib/check_include_guards.py
+++ b/tools/distrib/check_include_guards.py
@@ -200,6 +200,6 @@
 
 for filename in filename_list:
   if filename in KNOWN_BAD: continue
-  ok = validator.check(filename, args.fix)
+  ok = ok and validator.check(filename, args.fix)
 
 sys.exit(0 if ok else 1)
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index 510c26b..79c4071 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -29,4 +29,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION='1.0.1rc1'
+VERSION='1.1.0.dev0'
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index 762d694..a07a586 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -54,6 +54,11 @@
 
 PY3 = sys.version_info.major == 3
 
+# Environment variable to determine whether or not the Cython extension should
+# *use* Cython or use the generated C files. Note that this requires the C files
+# to have been generated by building first *with* Cython support.
+BUILD_WITH_CYTHON = os.environ.get('GRPC_PYTHON_BUILD_WITH_CYTHON', False)
+
 # There are some situations (like on Windows) where CC, CFLAGS, and LDFLAGS are
 # entirely ignored/dropped/forgotten by distutils and its Cygwin/MinGW support.
 # We use these environment variables to thus get around that without locking
@@ -147,17 +152,19 @@
     proto_files.append(relative_target)
   return {GRPC_PYTHON_TOOLS_PACKAGE: proto_files}
 
-def protoc_ext_module():
-  plugin_sources = [
-      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]
+def extension_modules():
+  if BUILD_WITH_CYTHON:
+    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', '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',
-      sources=(
-          [os.path.join('grpc', 'tools', '_protoc_compiler.pyx')] +
-          plugin_sources),
+      sources=plugin_sources,
       include_dirs=[
           '.',
           'grpc_root',
@@ -169,19 +176,18 @@
       extra_compile_args=list(EXTRA_COMPILE_ARGS),
       extra_link_args=list(EXTRA_LINK_ARGS),
   )
-  return plugin_ext
-
-def maybe_cythonize(exts):
-  from Cython import Build
-  return Build.cythonize(exts)
+  extensions = [plugin_ext]
+  if BUILD_WITH_CYTHON:
+    from Cython import Build
+    return Build.cythonize(extensions)
+  else:
+    return extensions
 
 setuptools.setup(
   name='grpcio_tools',
   version=grpc_version.VERSION,
   license='3-clause BSD',
-  ext_modules=maybe_cythonize([
-      protoc_ext_module(),
-  ]),
+  ext_modules=extension_modules(),
   packages=setuptools.find_packages('.'),
   namespace_packages=['grpc'],
   install_requires=[
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 eab7611..462c65a 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
@@ -31,7 +31,7 @@
 set -e
 
 # directories to run against
-DIRS="src/core/lib src/core/ext src/cpp test/core test/cpp include"
+DIRS="src/core/lib src/core/ext src/cpp test/core test/cpp include src/compiler"
 
 # file matching patterns to check
 GLOB="*.h *.c *.cc"
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index da1d2c6..087cc4e 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #================
 # C# dependencies
 
diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
index bbd903e..aa77d5f 100644
--- a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index ec71a53..05e963d 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
@@ -32,5 +32,20 @@
 # Using login shell removes Go from path, so we add it.
 RUN ln -s /usr/local/go/bin/go /usr/local/bin
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
index ec71a53..05e963d 100644
--- a/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
@@ -32,5 +32,20 @@
 # Using login shell removes Go from path, so we add it.
 RUN ln -s /usr/local/go/bin/go /usr/local/bin
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
index 252c9bc..b5fe54f 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
@@ -47,6 +47,21 @@
 ENV PATH $PATH:$JAVA_HOME/bin
 
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 
 # Trigger download of as many Gradle artifacts as possible.
 RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && \
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index be07094..d9a7501 100644
--- a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #==================
 # Node dependencies
 
diff --git a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index 8e7319c..10a8891 100644
--- a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -76,7 +76,7 @@
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
index 88b5130..dae64e5 100644
--- a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #==================
 # Ruby dependencies
 
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
index 4bd89b7..3288253 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile
index 556a26e..e082da6 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_cxx/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile
index 2a875f5..1e2b7d8 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_go/Dockerfile
@@ -34,6 +34,21 @@
 RUN pip install --upgrade google-api-python-client
 
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Using login shell removes Go from path, so we add it.
 RUN ln -s /usr/local/go/bin/go /usr/local/bin
 
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile
index 69bef14..0c17ff5 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_java/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile
index 0738e95..0594f69 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_node/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #==================
 # Node dependencies
 
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile
index 13afa15..0716be5 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_php/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #==================
 # Ruby dependencies
 
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_python/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_python/Dockerfile
index ee6249d..20d2d3f 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_python/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_python/Dockerfile
@@ -93,7 +93,7 @@
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
 
 
 RUN pip install coverage
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile
index 36b54dd..f459153 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_ruby/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
index 46d1a9d..4921815 100644
--- a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #================
 # C# dependencies
 
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
index da1d2c6..087cc4e 100644
--- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #================
 # C# dependencies
 
diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index a8aa74d..67cee19 100644
--- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
index abd3e42..bee0849 100644
--- a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
index 5ef25e8..2b3f4af 100644
--- a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
index c65fc61..2d28227 100644
--- a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile b/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile
index 9d5dd52..c250333 100644
--- a/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_wheezy_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/test/fuzzer/Dockerfile b/tools/dockerfile/test/fuzzer/Dockerfile
index 3ac134a..bd04f07 100644
--- a/tools/dockerfile/test/fuzzer/Dockerfile
+++ b/tools/dockerfile/test/fuzzer/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # C++ dependencies
 RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index adb554d..2540b52 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -133,7 +133,7 @@
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index be07094..d9a7501 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #==================
 # Node dependencies
 
diff --git a/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
index c0b394e..2213389 100644
--- a/tools/dockerfile/test/php7_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
@@ -88,7 +88,7 @@
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
index 91e8a90..17ea36b 100644
--- a/tools/dockerfile/test/php_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #=================
 # PHP dependencies
 
diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile
index 8e7319c..10a8891 100644
--- a/tools/dockerfile/test/python_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile
@@ -76,7 +76,7 @@
 # Install Python packages from PyPI
 RUN pip install pip --upgrade
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
index 88b5130..dae64e5 100644
--- a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #==================
 # Ruby dependencies
 
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index 70a32c5..f4b4831 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -63,6 +63,21 @@
 # Build profiling
 RUN apt-get update && apt-get install -y time && apt-get clean
 
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 six==1.10.0
+
 #========================
 # Sanity test dependencies
 RUN apt-get update && apt-get install -y \
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 323f5f6..314a42d 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.1-pre1
+PROJECT_NUMBER         = 1.1.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 8d38d9a..12eb651 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.1-pre1
+PROJECT_NUMBER         = 1.1.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -870,6 +870,7 @@
 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/core/lib/channel/channel_args.h \
@@ -878,6 +879,7 @@
 src/core/lib/channel/compress_filter.h \
 src/core/lib/channel/connected_channel.h \
 src/core/lib/channel/context.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/compression/algorithm_metadata.h \
@@ -948,6 +950,7 @@
 src/core/lib/transport/metadata.h \
 src/core/lib/transport/metadata_batch.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/cpp/client/secure_credentials.cc \
@@ -965,6 +968,7 @@
 src/cpp/client/generic_stub.cc \
 src/cpp/client/insecure_credentials.cc \
 src/cpp/common/channel_arguments.cc \
+src/cpp/common/channel_filter.cc \
 src/cpp/common/completion_queue.cc \
 src/cpp/common/core_codegen.cc \
 src/cpp/common/rpc_method.cc \
@@ -987,6 +991,7 @@
 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/handshaker.c \
 src/core/lib/channel/http_client_filter.c \
 src/core/lib/channel/http_server_filter.c \
 src/core/lib/compression/compression.c \
@@ -1067,6 +1072,7 @@
 src/core/lib/transport/metadata.c \
 src/core/lib/transport/metadata_batch.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/cpp/codegen/codegen_init.cc
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index 991531f..27f878e 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.1-pre1
+PROJECT_NUMBER         = 1.1.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index c8d53eb..426c6d9 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.0.1-pre1
+PROJECT_NUMBER         = 1.1.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -796,6 +796,7 @@
 src/core/lib/channel/compress_filter.h \
 src/core/lib/channel/connected_channel.h \
 src/core/lib/channel/context.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/compression/algorithm_metadata.h \
@@ -866,6 +867,7 @@
 src/core/lib/transport/metadata.h \
 src/core/lib/transport/metadata_batch.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 \
@@ -887,7 +889,6 @@
 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/timeout_encoding.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 \
@@ -930,6 +931,7 @@
 src/core/ext/client_config/subchannel_call_holder.h \
 src/core/ext/client_config/subchannel_index.h \
 src/core/ext/client_config/uri_parser.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 \
@@ -939,11 +941,13 @@
 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/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/lib/surface/init.c \
 src/core/lib/channel/channel_args.c \
@@ -951,6 +955,7 @@
 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/handshaker.c \
 src/core/lib/channel/http_client_filter.c \
 src/core/lib/channel/http_server_filter.c \
 src/core/lib/compression/compression.c \
@@ -1031,6 +1036,7 @@
 src/core/lib/transport/metadata.c \
 src/core/lib/transport/metadata_batch.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 \
@@ -1053,7 +1059,6 @@
 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/timeout_encoding.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 \
@@ -1109,6 +1114,7 @@
 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 \
@@ -1120,6 +1126,7 @@
 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/grpc_context.c \
@@ -1129,6 +1136,7 @@
 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/tracing.c \
 src/core/plugin_registry/grpc_plugin_registry.c \
 include/grpc/support/alloc.h \
diff --git a/tools/gce/create_linux_worker.sh b/tools/gce/create_linux_worker.sh
index c41e4d2..7bf8b24 100755
--- a/tools/gce/create_linux_worker.sh
+++ b/tools/gce/create_linux_worker.sh
@@ -43,7 +43,8 @@
     --project="$CLOUD_PROJECT" \
     --zone "$ZONE" \
     --machine-type n1-standard-8 \
-    --image ubuntu-15-10 \
+    --image=ubuntu-1510 \
+    --image-project=grpc-testing \
     --boot-disk-size 1000
 
 echo 'Created GCE instance, waiting 60 seconds for it to come online.'
diff --git a/tools/gcp/stress_test/stress_test_utils.py b/tools/gcp/stress_test/stress_test_utils.py
index b821fc8..be50af3 100755
--- a/tools/gcp/stress_test/stress_test_utils.py
+++ b/tools/gcp/stress_test/stress_test_utils.py
@@ -121,7 +121,7 @@
       if not page['jobComplete']:
         print('TIMEOUT ERROR: The query %s timed out. Current timeout value is'
               ' %d msec. Returning False (i.e assuming there are no failures)'
-             ) % (query, timeoout_msec)
+             ) % (query, timeout_msec)
         return False
 
       num_failures = int(page['totalRows'])
diff --git a/tools/gource/gen-all-logs.sh b/tools/gource/gen-all-logs.sh
index 85352c5..ab60c3c 100755
--- a/tools/gource/gen-all-logs.sh
+++ b/tools/gource/gen-all-logs.sh
@@ -41,7 +41,6 @@
   git clone https://github.com/grpc/$repo.git
   cd $repo
   gource --output-custom-log $tmpdir/logs/$repo
-  sed -i .backup "s,\|/,\|/$repo/,g" $tmpdir/logs/$repo
+  sed -i "s,|/,|/$repo/,g" $tmpdir/logs/$repo
 done
-rm $tmpdir/logs/*.backup
 cat $tmpdir/logs/* | sort -n > $outdir/all-logs.txt
diff --git a/tools/gource/gource.sh b/tools/gource/gource.sh
index b3dad5d..5529b32 100755
--- a/tools/gource/gource.sh
+++ b/tools/gource/gource.sh
@@ -34,7 +34,7 @@
   --max-file-lag 0.05           \
   --max-files 0                 \
   -e 0.01                       \
-  --hide filenames,dirnames     \
+  --hide filenames,dirnames,mouse,progress     \
   --disable-auto-rotate         \
   --file-filter '/grpc/doc/ref' \
   $*
diff --git a/tools/gource/make-video.sh b/tools/gource/make-video.sh
index 02d79df..cde0437 100755
--- a/tools/gource/make-video.sh
+++ b/tools/gource/make-video.sh
@@ -37,7 +37,7 @@
   --stop-at-end         \
   --output-ppm-stream - \
   $@ |                  \
-ffmpeg                  \
+avconv                  \
   -y                    \
   -r 60                 \
   -f image2pipe         \
diff --git a/tools/grift/Dockerfile b/tools/grift/Dockerfile
new file mode 100644
index 0000000..223ee93
--- /dev/null
+++ b/tools/grift/Dockerfile
@@ -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.
+
+FROM ubuntu:14.04
+
+RUN apt-get update && \
+  apt-get install -y \
+  git build-essential \
+  pkg-config flex \
+  bison \
+  libkrb5-dev \
+  libsasl2-dev \
+  libnuma-dev \
+  pkg-config \
+  libssl-dev \
+  autoconf libtool \
+  cmake \
+  libiberty-dev \
+  g++ unzip \
+  curl make automake libtool libboost-dev
+
+# Configure git
+RUN git config --global user.name "Jenkins" && \
+  git config --global user.email "jenkins@grpc"
+
+# Clone gRPC
+RUN git clone https://github.com/grpc/grpc
+
+# Update Submodules
+RUN cd grpc && git submodule update --init
+
+# Install protobuf
+RUN cd grpc/third_party/protobuf && ./autogen.sh && ./configure && \
+  make -j && make check -j && make install && ldconfig
+
+# Install gRPC
+RUN cd grpc && make -j && make install
+
+# Install thrift
+RUN cd grpc/third_party/thrift && git am --signoff < ../../tools/grift/grpc_plugins_generator.patch && \
+  ./bootstrap.sh && ./configure && make -j && make install
\ No newline at end of file
diff --git a/tools/grift/README.md b/tools/grift/README.md
new file mode 100644
index 0000000..7cbbdc5
--- /dev/null
+++ b/tools/grift/README.md
@@ -0,0 +1,26 @@
+Copyright 2016 Google Inc.
+
+#Documentation
+
+grift is integration of [Apache Thrift](https://github.com/apache/thrift.git) Serializer with gRPC.
+
+This integration allows you to use grpc to send thrift messages in C++ and java.
+
+grift uses Compact Protocol to serialize thrift messages. 
+
+##generating grpc plugins for thrift services
+
+###CPP
+```sh
+ $ thrift --gen cpp <thrift-file>
+```
+
+###JAVA
+```sh
+ $ thrift --gen java <thrift-file>
+```
+
+#Installation
+
+Before Installing thrift make sure to apply this [patch](grpc_plugins_generator.patch) to third_party/thrift.
+Go to third_party/thrift and follow the [INSTALLATION](https://github.com/apache/thrift.git) instructions to install thrift with commit id bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c.
\ No newline at end of file
diff --git a/tools/grift/grpc_plugins_generator.patch b/tools/grift/grpc_plugins_generator.patch
new file mode 100644
index 0000000..de82a01
--- /dev/null
+++ b/tools/grift/grpc_plugins_generator.patch
@@ -0,0 +1,2505 @@
+From 0894590b5020c38106d4ebb2291994668c64f9dd Mon Sep 17 00:00:00 2001
+From: chedeti <chedeti@google.com>
+Date: Sun, 31 Jul 2016 15:47:47 -0700
+Subject: [PATCH 1/3] don't build tests
+
+---
+ Makefile.am         | 7 ++-----
+ lib/cpp/Makefile.am | 7 ++-----
+ 2 files changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/Makefile.am b/Makefile.am
+index 10fe49a..d49caac 100755
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -21,10 +21,6 @@ ACLOCAL_AMFLAGS = -I ./aclocal
+ 
+ SUBDIRS = compiler/cpp lib
+ 
+-if WITH_TESTS
+-SUBDIRS += test
+-endif
+-
+ if WITH_TUTORIAL
+ SUBDIRS += tutorial
+ endif
+@@ -117,4 +113,5 @@ EXTRA_DIST = \
+ 	CHANGES \
+ 	NOTICE \
+ 	README.md \
+-	Thrift.podspec
++	Thrift.podspec \
++	test
+diff --git a/lib/cpp/Makefile.am b/lib/cpp/Makefile.am
+index 6fd15d2..7de1fad 100755
+--- a/lib/cpp/Makefile.am
++++ b/lib/cpp/Makefile.am
+@@ -27,10 +27,6 @@ moc__%.cpp: %.h
+ 
+ SUBDIRS = .
+ 
+-if WITH_TESTS
+-SUBDIRS += test
+-endif
+-
+ pkgconfigdir = $(libdir)/pkgconfig
+ 
+ lib_LTLIBRARIES = libthrift.la
+@@ -277,7 +273,8 @@ EXTRA_DIST = \
+              thrift-qt.pc.in \
+              thrift-qt5.pc.in \
+              src/thrift/qt/CMakeLists.txt \
+-             $(WINDOWS_DIST)
++             $(WINDOWS_DIST) \
++             test
+ 
+ style-local:
+ 	$(CPPSTYLE_CMD)
+-- 
+2.8.0.rc3.226.g39d4020
+
+
+From 387e4300bc9d98176a92a7c010621443a538e7f2 Mon Sep 17 00:00:00 2001
+From: chedeti <chedeti@google.com>
+Date: Sun, 31 Jul 2016 16:16:40 -0700
+Subject: [PATCH 2/3] grpc cpp plugins generator with example
+
+---
+ compiler/cpp/src/generate/t_cpp_generator.cc | 489 +++++++++++++++++++++++----
+ tutorial/cpp/CMakeLists.txt                  |  53 ---
+ tutorial/cpp/CppClient.cpp                   |  80 -----
+ tutorial/cpp/CppServer.cpp                   | 181 ----------
+ tutorial/cpp/GriftClient.cpp                 |  93 +++++
+ tutorial/cpp/GriftServer.cpp                 |  93 +++++
+ tutorial/cpp/Makefile.am                     |  66 ++--
+ tutorial/cpp/test.thrift                     |  13 +
+ 8 files changed, 652 insertions(+), 416 deletions(-)
+ delete mode 100644 tutorial/cpp/CMakeLists.txt
+ delete mode 100644 tutorial/cpp/CppClient.cpp
+ delete mode 100644 tutorial/cpp/CppServer.cpp
+ create mode 100644 tutorial/cpp/GriftClient.cpp
+ create mode 100644 tutorial/cpp/GriftServer.cpp
+ create mode 100644 tutorial/cpp/test.thrift
+
+diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
+index 6c04899..1557241 100644
+--- a/compiler/cpp/src/generate/t_cpp_generator.cc
++++ b/compiler/cpp/src/generate/t_cpp_generator.cc
+@@ -162,6 +162,8 @@ public:
+                                  bool specialized = false);
+   void generate_function_helpers(t_service* tservice, t_function* tfunction);
+   void generate_service_async_skeleton(t_service* tservice);
++  void generate_service_stub_interface(t_service* tservice);
++  void generate_service_stub(t_service* tservice);
+ 
+   /**
+    * Serialization constructs
+@@ -883,10 +885,10 @@ void t_cpp_generator::generate_struct_declaration(ofstream& out,
+                                                   bool is_user_struct) {
+   string extends = "";
+   if (is_exception) {
+-    extends = " : public ::apache::thrift::TException";
++    extends = " : public apache::thrift::TException";
+   } else {
+-    if (is_user_struct && !gen_templates_) {
+-      extends = " : public virtual ::apache::thrift::TBase";
++    if (!gen_templates_) {
++      extends = " : public virtual apache::thrift::TBase";
+     }
+   }
+ 
+@@ -1130,9 +1132,15 @@ void t_cpp_generator::generate_struct_definition(ofstream& out,
+   vector<t_field*>::const_iterator m_iter;
+   const vector<t_field*>& members = tstruct->get_members();
+ 
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
++
+   // Destructor
+   if (tstruct->annotations_.find("final") == tstruct->annotations_.end()) {
+-    force_cpp_out << endl << indent() << tstruct->get_name() << "::~" << tstruct->get_name()
++    force_cpp_out << endl << indent() << method_prefix <<
++    tstruct->get_name() << "::~" << tstruct->get_name()
+                   << "() throw() {" << endl;
+     indent_up();
+ 
+@@ -1145,12 +1153,14 @@ void t_cpp_generator::generate_struct_definition(ofstream& out,
+     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+       if (is_reference((*m_iter))) {
+         std::string type = type_name((*m_iter)->get_type());
+-        out << endl << indent() << "void " << tstruct->get_name() << "::__set_"
++        out << endl << indent() << "void " << method_prefix
++            << tstruct->get_name() << "::__set_"
+             << (*m_iter)->get_name() << "(boost::shared_ptr<"
+             << type_name((*m_iter)->get_type(), false, false) << ">";
+         out << " val) {" << endl;
+       } else {
+-        out << endl << indent() << "void " << tstruct->get_name() << "::__set_"
++        out << endl << indent() << "void " << method_prefix
++            << tstruct->get_name() << "::__set_"
+             << (*m_iter)->get_name() << "(" << type_name((*m_iter)->get_type(), false, true);
+         out << " val) {" << endl;
+       }
+@@ -1177,11 +1187,16 @@ void t_cpp_generator::generate_struct_definition(ofstream& out,
+  * @param tstruct The struct
+  */
+ void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct, bool pointers) {
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
++
+   if (gen_templates_) {
+     out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+-        << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl;
++        << method_prefix << tstruct->get_name() << "::read(Protocol_* iprot) {" << endl;
+   } else {
+-    indent(out) << "uint32_t " << tstruct->get_name()
++    indent(out) << "uint32_t " << method_prefix << tstruct->get_name()
+                 << "::read(::apache::thrift::protocol::TProtocol* iprot) {" << endl;
+   }
+   indent_up();
+@@ -1301,14 +1316,18 @@ void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct, b
+  */
+ void t_cpp_generator::generate_struct_writer(ofstream& out, t_struct* tstruct, bool pointers) {
+   string name = tstruct->get_name();
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
+   const vector<t_field*>& fields = tstruct->get_sorted_members();
+   vector<t_field*>::const_iterator f_iter;
+ 
+   if (gen_templates_) {
+     out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+-        << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
++        << method_prefix << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
+   } else {
+-    indent(out) << "uint32_t " << tstruct->get_name()
++    indent(out) << "uint32_t " << method_prefix << tstruct->get_name()
+                 << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+   }
+   indent_up();
+@@ -1369,14 +1388,18 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+                                                     t_struct* tstruct,
+                                                     bool pointers) {
+   string name = tstruct->get_name();
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
+   const vector<t_field*>& fields = tstruct->get_sorted_members();
+   vector<t_field*>::const_iterator f_iter;
+ 
+   if (gen_templates_) {
+     out << indent() << "template <class Protocol_>" << endl << indent() << "uint32_t "
+-        << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
++        << method_prefix << tstruct->get_name() << "::write(Protocol_* oprot) const {" << endl;
+   } else {
+-    indent(out) << "uint32_t " << tstruct->get_name()
++    indent(out) << "uint32_t " << method_prefix << tstruct->get_name()
+                 << "::write(::apache::thrift::protocol::TProtocol* oprot) const {" << endl;
+   }
+   indent_up();
+@@ -1385,18 +1408,7 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+ 
+   indent(out) << "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
+ 
+-  bool first = true;
+   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+-    if (first) {
+-      first = false;
+-      out << endl << indent() << "if ";
+-    } else {
+-      out << " else if ";
+-    }
+-
+-    out << "(this->__isset." << (*f_iter)->get_name() << ") {" << endl;
+-
+-    indent_up();
+ 
+     // Write field header
+     out << indent() << "xfer += oprot->writeFieldBegin("
+@@ -1410,9 +1422,6 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+     }
+     // Write field closer
+     indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
+-
+-    indent_down();
+-    indent(out) << "}";
+   }
+ 
+   // Write the struct map
+@@ -1478,9 +1487,13 @@ void t_cpp_generator::generate_struct_ostream_operator(std::ofstream& out, t_str
+ }
+ 
+ void t_cpp_generator::generate_struct_print_method_decl(std::ofstream& out, t_struct* tstruct) {
++  string method_prefix = "";
++  if (service_name_ != "") {
++    method_prefix = service_name_ + "::";
++  }
+   out << "void ";
+   if (tstruct) {
+-    out << tstruct->get_name() << "::";
++    out << method_prefix << tstruct->get_name() << "::";
+   }
+   out << "printTo(std::ostream& out) const";
+ }
+@@ -1601,11 +1614,13 @@ void t_cpp_generator::generate_exception_what_method(std::ofstream& out, t_struc
+  */
+ void t_cpp_generator::generate_service(t_service* tservice) {
+   string svcname = tservice->get_name();
++  string ns = tservice->get_program()->get_namespace("cpp");
+ 
+   // Make output files
+-  string f_header_name = get_out_dir() + svcname + ".h";
++  string f_header_name = get_out_dir() + svcname + ".grpc.thrift.h";
+   f_header_.open(f_header_name.c_str());
+ 
++
+   // Print header file includes
+   f_header_ << autogen_comment();
+   f_header_ << "#ifndef " << svcname << "_H" << endl << "#define " << svcname << "_H" << endl
+@@ -1621,15 +1636,38 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     f_header_ << "#include <thrift/async/TAsyncDispatchProcessor.h>" << endl;
+   }
+   f_header_ << "#include <thrift/async/TConcurrentClientSyncInfo.h>" << endl;
++
+   f_header_ << "#include \"" << get_include_prefix(*get_program()) << program_name_ << "_types.h\""
+             << endl;
+ 
+   t_service* extends_service = tservice->get_extends();
+-  if (extends_service != NULL) {
++  if (extends_service) {
+     f_header_ << "#include \"" << get_include_prefix(*(extends_service->get_program()))
+-              << extends_service->get_name() << ".h\"" << endl;
++              << extends_service->get_name() << ".grpc.thrift.h\"" << endl;
+   }
+ 
++
++  f_header_  <<
++      "#include <grpc++/impl/codegen/async_stream.h>" << endl <<
++      "#include <grpc++/impl/codegen/async_unary_call.h>"  << endl <<
++      "#include <grpc++/impl/codegen/thrift_utils.h>" << endl <<
++      "#include <grpc++/impl/codegen/rpc_method.h>"  << endl <<
++      "#include <grpc++/impl/codegen/service_type.h>"  << endl <<
++      "#include <grpc++/impl/codegen/status.h>" << endl <<
++      "#include <grpc++/impl/codegen/stub_options.h>" << endl <<
++      "#include <grpc++/impl/codegen/sync_stream.h>" << endl;
++
++
++  f_header_  <<
++      endl <<
++      "namespace grpc {" << endl <<
++      "class CompletionQueue;"  << endl <<
++      "class Channel;"  << endl <<
++      "class RpcService;"  << endl <<
++      "class ServerCompletionQueue;"  << endl <<
++      "class ServerContext;" << endl <<
++      "}" << endl;
++
+   f_header_ << endl << ns_open_ << endl << endl;
+ 
+   f_header_ << "#ifdef _WIN32\n"
+@@ -1638,10 +1676,13 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+                "#endif\n\n";
+ 
+   // Service implementation file includes
+-  string f_service_name = get_out_dir() + svcname + ".cpp";
++  string f_service_name = get_out_dir() + svcname + ".grpc.thrift.cpp";
+   f_service_.open(f_service_name.c_str());
+   f_service_ << autogen_comment();
+-  f_service_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\"" << endl;
++
++  f_service_ << "#include \"" <<
++    get_include_prefix(*get_program()) << svcname << ".grpc.thrift.h\"" << endl;
++
+   if (gen_cob_style_) {
+     f_service_ << "#include \"thrift/async/TAsyncChannel.h\"" << endl;
+   }
+@@ -1652,7 +1693,7 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     string f_service_tcc_name = get_out_dir() + svcname + ".tcc";
+     f_service_tcc_.open(f_service_tcc_name.c_str());
+     f_service_tcc_ << autogen_comment();
+-    f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".h\""
++    f_service_tcc_ << "#include \"" << get_include_prefix(*get_program()) << svcname << ".grpc.thrift.h\""
+                    << endl;
+ 
+     f_service_tcc_ << "#ifndef " << svcname << "_TCC" << endl << "#define " << svcname << "_TCC"
+@@ -1663,19 +1704,69 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     }
+   }
+ 
++  f_service_ <<
++    endl <<
++    "#include <grpc++/impl/codegen/async_stream.h>" << endl <<
++    "#include <grpc++/impl/codegen/async_unary_call.h>" << endl <<
++    "#include <grpc++/impl/codegen/channel_interface.h>" << endl <<
++    "#include <grpc++/impl/codegen/client_unary_call.h>" << endl <<
++    "#include <grpc++/impl/codegen/method_handler_impl.h>" << endl <<
++    "#include <grpc++/impl/codegen/rpc_service_method.h>" << endl <<
++    "#include <grpc++/impl/codegen/service_type.h>" << endl <<
++    "#include <grpc++/impl/codegen/sync_stream.h>" << endl <<
++    endl;
++
+   f_service_ << endl << ns_open_ << endl << endl;
+   f_service_tcc_ << endl << ns_open_ << endl << endl;
+ 
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++
++  f_service_ <<
++    "static const char* " << service_name_ << "_method_names[] = {" << endl;
++
++
++  indent_up();
++
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "\"/" << ns << "." << service_name_ << "/" << (*f_iter)->get_name() << "\"," << endl;
++  }
++
++
++  t_service* service_iter = extends_service;  
++  while (service_iter) {
++    vector<t_function*> functions = service_iter->get_functions();
++    vector<t_function*>::iterator f_iter;
++
++    for ( f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++      indent() << "\"/" << service_iter->get_program()->get_namespace("cpp") <<
++      "." << service_iter->get_name() << "/" << (*f_iter)->get_name() << "\"," << endl;
++    }
++    service_iter = service_iter->get_extends();
++  }
++
++  indent_down();
++  f_service_ <<
++  "};" << endl;
++
++  // Generate service class
++  if ( extends_service) {
++    f_header_ << "class " << service_name_ << " : public " <<
++      type_name(extends_service) << " {" << endl <<
++      "public:" << endl;
++  }
++  else {
++    f_header_ << "class " << service_name_ << "{" << endl <<
++      "public:" << endl;
++  }
++
+   // Generate all the components
+-  generate_service_interface(tservice, "");
+-  generate_service_interface_factory(tservice, "");
+-  generate_service_null(tservice, "");
+   generate_service_helpers(tservice);
+-  generate_service_client(tservice, "");
+-  generate_service_processor(tservice, "");
+-  generate_service_multiface(tservice);
+-  generate_service_skeleton(tservice);
+-  generate_service_client(tservice, "Concurrent");
++  generate_service_interface(tservice, "");
++  generate_service_stub_interface(tservice);
++  generate_service_stub(tservice);
+ 
+   // Generate all the cob components
+   if (gen_cob_style_) {
+@@ -1688,10 +1779,14 @@ void t_cpp_generator::generate_service(t_service* tservice) {
+     generate_service_async_skeleton(tservice);
+   }
+ 
++   // Close service class
++  f_header_ << "};" << endl;
++
+   f_header_ << "#ifdef _WIN32\n"
+                "  #pragma warning( pop )\n"
+                "#endif\n\n";
+ 
++
+   // Close the namespace
+   f_service_ << ns_close_ << endl << endl;
+   f_service_tcc_ << ns_close_ << endl << endl;
+@@ -1729,15 +1824,11 @@ void t_cpp_generator::generate_service_helpers(t_service* tservice) {
+     string name_orig = ts->get_name();
+ 
+     // TODO(dreiss): Why is this stuff not in generate_function_helpers?
+-    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_args");
++    ts->set_name((*f_iter)->get_name() + "Req");
+     generate_struct_declaration(f_header_, ts, false);
+-    generate_struct_definition(out, f_service_, ts, false);
++    generate_struct_definition(out, f_service_, ts, true);
+     generate_struct_reader(out, ts);
+     generate_struct_writer(out, ts);
+-    ts->set_name(tservice->get_name() + "_" + (*f_iter)->get_name() + "_pargs");
+-    generate_struct_declaration(f_header_, ts, false, true, false, true);
+-    generate_struct_definition(out, f_service_, ts, false);
+-    generate_struct_writer(out, ts, true);
+     ts->set_name(name_orig);
+ 
+     generate_function_helpers(tservice, *f_iter);
+@@ -1745,13 +1836,218 @@ void t_cpp_generator::generate_service_helpers(t_service* tservice) {
+ }
+ 
+ /**
++ *  Generates a service Stub Interface
++ *
++ * @param tservice The service to generate a stub for.
++ *
++ */
++void t_cpp_generator::generate_service_stub_interface(t_service* tservice) {
++
++    string extends = "";
++    if (tservice->get_extends()) {
++      extends = " : virtual public " + type_name(tservice->get_extends()) + "::StubInterface";
++    }
++
++    f_header_ <<
++    endl <<
++    "class StubInterface " << extends << " {" << endl;
++    indent_up();
++    f_header_ <<
++    " public:" << endl <<
++    indent() << "virtual ~StubInterface() {}" << endl;
++
++    vector<t_function*> functions = tservice->get_functions();
++    vector<t_function*>::iterator f_iter;
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_header_ <<
++        indent() << "virtual ::grpc::Status " << function_name <<
++        "(::grpc::ClientContext* context, const " << function_name <<
++        "Req& request, " << function_name << "Resp* response) = 0;" << endl;
++    }
++    indent_down();
++    f_header_ <<
++      "};" << endl << endl;
++
++}
++void t_cpp_generator::generate_service_stub(t_service* tservice) {
++    f_header_ <<
++    endl <<
++    "class Stub : public StubInterface {" <<
++    endl;
++
++    indent_up();
++    f_header_ <<
++    " public:" << endl <<
++    indent() << "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);" <<
++    endl;
++
++    vector<t_function*> functions = tservice->get_functions();
++    vector<t_function*>::iterator f_iter;
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_header_ <<
++        indent() << "::grpc::Status " << function_name <<
++        "(::grpc::ClientContext* context, const " << function_name <<
++        "Req& request, " << function_name << "Resp* response) override;" << endl;
++    }
++
++    t_service* extends_service = tservice->get_extends();
++    t_service* service_iter = extends_service;
++    while (service_iter) {
++      // generate inherited methods
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++        string function_name = (*f_iter)->get_name();
++        f_header_ <<
++          indent() << "::grpc::Status " << function_name <<
++          "(::grpc::ClientContext* context, const " << function_name <<
++          "Req& request, " << function_name << "Resp* response) override;" << endl;
++      }
++      service_iter = service_iter->get_extends();
++    }
++
++    f_header_ <<
++    endl <<
++    " private:" << endl <<
++    indent() << "std::shared_ptr< ::grpc::ChannelInterface> channel_;" <<
++    endl;
++
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_header_ <<
++        indent() << "const ::grpc::RpcMethod rpcmethod_" << (*f_iter)->get_name() << "_;" << endl;
++    }
++
++    service_iter = extends_service;
++    while (service_iter) {
++      // generate inherited methods
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++        f_header_ <<
++          indent() << "const ::grpc::RpcMethod rpcmethod_" << (*f_iter)->get_name() << "_;" << endl;
++      }
++      service_iter = service_iter->get_extends();
++    }
++
++    indent_down();
++    f_header_ <<
++      "};" << endl << endl;
++
++    // generate the implementaion of Stub
++    f_service_ <<
++      endl <<
++      service_name_ << "::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel)" << endl;
++
++    indent_up();
++    f_service_ <<
++    indent() << ": channel_(channel)" << endl;
++    int i=0;
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter , ++i) {
++      f_service_ <<
++        indent() <<
++        ", rpcmethod_" << (*f_iter)->get_name() << "_(" <<
++        service_name_ << "_method_names[" << i << "], ::grpc::RpcMethod::NORMAL_RPC, channel)" << endl;
++    }
++
++    service_iter = extends_service;
++    while (service_iter) {
++      // generate inherited methods
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter, ++i) {
++        f_service_ <<
++        indent() <<
++        ", rpcmethod_" << (*f_iter)->get_name() << "_(" <<
++        service_name_ << "_method_names[" << i << "], ::grpc::RpcMethod::NORMAL_RPC, channel)" << endl;
++      }
++      service_iter = service_iter->get_extends();
++    }
++    f_service_ <<
++    indent() << "{}" << endl;
++    indent_down();
++
++    // generate NewStub
++    f_header_ <<
++    endl <<
++    "static std::unique_ptr<Stub> NewStub(const std::shared_ptr\
++    < ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());" <<
++    endl;
++
++    // generate NewStub Implementation
++    f_service_ <<
++    endl <<
++    "std::unique_ptr< " << service_name_ << "::Stub> " << service_name_ << "::NewStub(const std::shared_ptr\
++    < ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {" << endl;
++
++    indent_up();
++    f_service_ <<
++    indent() << "std::unique_ptr< " << service_name_ << "::Stub> stub(new " << service_name_ <<
++    "::Stub(channel));" << endl <<
++    indent() << "return stub;" << endl;
++    indent_down();
++    f_service_ <<
++    "}" << endl;
++
++    // generate stub methods
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_service_ <<
++        endl <<
++        "::grpc::Status " << service_name_ << "::Stub::" <<  function_name <<
++        "(::grpc::ClientContext* context, const " << service_name_ << "::" <<
++        function_name << "Req& request, " << service_name_ << "::" <<
++        function_name << "Resp* response) {" << endl;
++
++      indent_up();
++      f_service_ <<
++      indent() << "return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_" <<
++      function_name << "_, context, request, response);" << endl;
++      indent_down();
++
++      f_service_ <<
++      "}" << endl;
++
++    }
++
++    service_iter = extends_service;
++    while (service_iter) {
++      vector<t_function*> functions = service_iter->get_functions();
++      vector<t_function*>::iterator f_iter;
++      for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++        string function_name = (*f_iter)->get_name();
++        f_service_ <<
++          endl <<
++          "::grpc::Status " << service_name_ << "::Stub::" <<  function_name <<
++          "(::grpc::ClientContext* context, const " << service_name_ << "::" <<
++          function_name << "Req& request, " << service_name_ << "::" <<
++          function_name << "Resp* response) {" << endl;
++
++        indent_up();
++        f_service_ <<
++        indent() << "return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_" <<
++        function_name << "_, context, request, response);" << endl;
++        indent_down();
++
++        f_service_ <<
++        "}" << endl;
++
++      }
++      service_iter = service_iter->get_extends();
++    }
++
++}
++
++
++/**
+  * Generates a service interface definition.
+  *
+  * @param tservice The service to generate a header definition for
+  */
+ void t_cpp_generator::generate_service_interface(t_service* tservice, string style) {
+ 
+-  string service_if_name = service_name_ + style + "If";
++  string service_if_name = "Service";
+   if (style == "CobCl") {
+     // Forward declare the client.
+     string client_name = service_name_ + "CobClient";
+@@ -1764,13 +2060,15 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+   }
+ 
+   string extends = "";
+-  if (tservice->get_extends() != NULL) {
+-    extends = " : virtual public " + type_name(tservice->get_extends()) + style + "If";
++  if (tservice->get_extends()) {
++    extends = " : virtual public " + type_name(tservice->get_extends()) + style + "::Service";
+     if (style == "CobCl" && gen_templates_) {
+       // TODO(simpkins): If gen_templates_ is enabled, we currently assume all
+       // parent services were also generated with templates enabled.
+       extends += "T<Protocol_>";
+     }
++  } else {
++    extends = " : public ::grpc::Service";
+   }
+ 
+   if (style == "CobCl" && gen_templates_) {
+@@ -1778,7 +2076,9 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+   }
+   f_header_ << "class " << service_if_name << extends << " {" << endl << " public:" << endl;
+   indent_up();
+-  f_header_ << indent() << "virtual ~" << service_if_name << "() {}" << endl;
++
++  f_header_ << indent() << "Service();" << endl;
++  f_header_ << indent() << "virtual ~Service();" << endl;
+ 
+   vector<t_function*> functions = tservice->get_functions();
+   vector<t_function*>::iterator f_iter;
+@@ -1786,7 +2086,12 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+     if ((*f_iter)->has_doc())
+       f_header_ << endl;
+     generate_java_doc(f_header_, *f_iter);
+-    f_header_ << indent() << "virtual " << function_signature(*f_iter, style) << " = 0;" << endl;
++
++    string function_name = (*f_iter)->get_name();
++    f_header_ <<
++      indent() << "virtual ::grpc::Status " << function_name <<
++      "(::grpc::ServerContext* context, const "<< function_name <<
++      "Req* request, "<< function_name << "Resp* response);" << endl;
+   }
+   indent_down();
+   f_header_ << "};" << endl << endl;
+@@ -1797,6 +2102,66 @@ void t_cpp_generator::generate_service_interface(t_service* tservice, string sty
+     f_header_ << "typedef " << service_if_name << "< ::apache::thrift::protocol::TProtocol> "
+               << service_name_ << style << "If;" << endl << endl;
+   }
++
++   // generate the service interface implementations
++
++    f_service_ <<
++    endl <<
++    service_name_ << "::Service::Service() {" << endl;
++    indent_up();
++    f_service_ <<
++    indent() << "(void)" << service_name_ << "_method_names;" << endl;
++    uint32_t i=0;
++    for(i=0;i<functions.size(); i++) {
++      string function_name = functions[i]->get_name();
++      f_service_ <<
++        endl <<
++        indent() << "AddMethod(new ::grpc::RpcServiceMethod(" << endl;
++        indent_up();
++
++      f_service_ <<
++        indent() << service_name_ << "_method_names[" << i << "]," << endl <<
++        indent() << "::grpc::RpcMethod::NORMAL_RPC," << endl <<
++        indent() << "new ::grpc::RpcMethodHandler< " << service_name_ << "::Service, " <<
++        service_name_ << "::" << function_name << "Req, " << service_name_ << "::" <<
++        function_name << "Resp>(" << endl;
++
++      indent_up();
++      f_service_ <<
++        indent() << "std::mem_fn(&" << service_name_ << "::Service::" << function_name << "), this)));" << endl;
++
++      indent_down();
++      indent_down();
++    }
++
++    indent_down();
++    f_service_ <<
++    "}" << endl;
++
++    f_service_ <<
++    endl <<
++    service_name_ << "::Service::~Service() {" << endl <<
++    "}" << endl;
++
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      string function_name = (*f_iter)->get_name();
++      f_service_ <<
++        endl <<
++        "::grpc::Status " << service_name_ << "::Service::" << function_name <<
++        "(::grpc::ServerContext* context, const " << service_name_ << "::" << function_name <<
++        "Req* request, " << service_name_ << "::" << function_name << "Resp* response) {" << endl;
++      indent_up();
++      f_service_ <<
++      indent() << "(void) context;" << endl <<
++      indent() << "(void) request;" << endl <<
++      indent() << "(void) response;" << endl <<
++      indent() << "return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED,\"\");" << endl;
++      indent_down();
++
++      f_service_ <<
++      "}" << endl;
++    }
++
+ }
+ 
+ /**
+@@ -3095,7 +3460,7 @@ void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function*
+ 
+   std::ofstream& out = (gen_templates_ ? f_service_tcc_ : f_service_);
+ 
+-  t_struct result(program_, tservice->get_name() + "_" + tfunction->get_name() + "_result");
++  t_struct result(program_, tfunction->get_name() + "Resp");
+   t_field success(tfunction->get_returntype(), "success", 0);
+   if (!tfunction->get_returntype()->is_void()) {
+     result.append(&success);
+@@ -3109,17 +3474,9 @@ void t_cpp_generator::generate_function_helpers(t_service* tservice, t_function*
+   }
+ 
+   generate_struct_declaration(f_header_, &result, false);
+-  generate_struct_definition(out, f_service_, &result, false);
++  generate_struct_definition(out, f_service_, &result, true);
+   generate_struct_reader(out, &result);
+   generate_struct_result_writer(out, &result);
+-
+-  result.set_name(tservice->get_name() + "_" + tfunction->get_name() + "_presult");
+-  generate_struct_declaration(f_header_, &result, false, true, true, gen_cob_style_);
+-  generate_struct_definition(out, f_service_, &result, false);
+-  generate_struct_reader(out, &result, true);
+-  if (gen_cob_style_) {
+-    generate_struct_writer(out, &result, true);
+-  }
+ }
+ 
+ /**
+@@ -3162,8 +3519,8 @@ void t_cpp_generator::generate_process_function(t_service* tservice,
+         << endl;
+     scope_up(out);
+ 
+-    string argsname = tservice->get_name() + "_" + tfunction->get_name() + "_args";
+-    string resultname = tservice->get_name() + "_" + tfunction->get_name() + "_result";
++    string argsname = tfunction->get_name() + "Req";
++    string resultname = tfunction->get_name() + "Resp";
+ 
+     if (tfunction->is_oneway() && !unnamed_oprot_seqid) {
+       out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl;
+@@ -3320,7 +3677,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice,
+       out << indent() << "(void) seqid;" << endl << indent() << "(void) oprot;" << endl;
+     }
+ 
+-    out << indent() << tservice->get_name() + "_" + tfunction->get_name() << "_args args;" << endl
++    out << indent() << tfunction->get_name() << "Req args;" << endl
+         << indent() << "void* ctx = NULL;" << endl << indent()
+         << "if (this->eventHandler_.get() != NULL) {" << endl << indent()
+         << "  ctx = this->eventHandler_->getContext(" << service_func_name << ", NULL);" << endl
+@@ -3487,7 +3844,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice,
+           << "this->eventHandler_.get(), ctx, " << service_func_name << ");" << endl << endl;
+ 
+       // Throw the TDelayedException, and catch the result
+-      out << indent() << tservice->get_name() << "_" << tfunction->get_name() << "_result result;"
++      out << indent() << tfunction->get_name() << "Resp result;"
+           << endl << endl << indent() << "try {" << endl;
+       indent_up();
+       out << indent() << "_throw->throw_it();" << endl << indent() << "return cob(false);"
+diff --git a/tutorial/cpp/CMakeLists.txt b/tutorial/cpp/CMakeLists.txt
+deleted file mode 100644
+index 8a3d085..0000000
+--- a/tutorial/cpp/CMakeLists.txt
++++ /dev/null
+@@ -1,53 +0,0 @@
+-#
+-# Licensed to the Apache Software Foundation (ASF) under one
+-# or more contributor license agreements. See the NOTICE file
+-# distributed with this work for additional information
+-# regarding copyright ownership. The ASF licenses this file
+-# to you under the Apache License, Version 2.0 (the
+-# "License"); you may not use this file except in compliance
+-# with the License. You may obtain a copy of the License at
+-#
+-#   http://www.apache.org/licenses/LICENSE-2.0
+-#
+-# Unless required by applicable law or agreed to in writing,
+-# software distributed under the License is distributed on an
+-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-# KIND, either express or implied. See the License for the
+-# specific language governing permissions and limitations
+-# under the License.
+-#
+-
+-find_package(Boost 1.53.0 REQUIRED)
+-include_directories(SYSTEM "${Boost_INCLUDE_DIRS}")
+-
+-#Make sure gen-cpp files can be included
+-include_directories("${CMAKE_CURRENT_BINARY_DIR}")
+-include_directories("${CMAKE_CURRENT_BINARY_DIR}/gen-cpp")
+-include_directories("${PROJECT_SOURCE_DIR}/lib/cpp/src")
+-
+-include(ThriftMacros)
+-
+-set(tutorialgencpp_SOURCES 
+-    gen-cpp/Calculator.cpp
+-    gen-cpp/SharedService.cpp
+-    gen-cpp/shared_constants.cpp
+-    gen-cpp/shared_types.cpp
+-    gen-cpp/tutorial_constants.cpp
+-    gen-cpp/tutorial_types.cpp
+-)
+-add_library(tutorialgencpp STATIC ${tutorialgencpp_SOURCES})
+-LINK_AGAINST_THRIFT_LIBRARY(tutorialgencpp thrift)
+-
+-add_custom_command(OUTPUT gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp
+-    COMMAND ${THRIFT_COMPILER} --gen cpp -r ${PROJECT_SOURCE_DIR}/tutorial/tutorial.thrift
+-)
+-
+-add_executable(TutorialServer CppServer.cpp)
+-target_link_libraries(TutorialServer tutorialgencpp)
+-LINK_AGAINST_THRIFT_LIBRARY(TutorialServer thrift)
+-target_link_libraries(TutorialServer ${ZLIB_LIBRARIES})
+-
+-add_executable(TutorialClient CppClient.cpp)
+-target_link_libraries(TutorialClient tutorialgencpp)
+-LINK_AGAINST_THRIFT_LIBRARY(TutorialClient thrift)
+-target_link_libraries(TutorialClient ${ZLIB_LIBRARIES})
+diff --git a/tutorial/cpp/CppClient.cpp b/tutorial/cpp/CppClient.cpp
+deleted file mode 100644
+index 2763fee..0000000
+--- a/tutorial/cpp/CppClient.cpp
++++ /dev/null
+@@ -1,80 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one
+- * or more contributor license agreements. See the NOTICE file
+- * distributed with this work for additional information
+- * regarding copyright ownership. The ASF licenses this file
+- * to you under the Apache License, Version 2.0 (the
+- * "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at
+- *
+- *   http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing,
+- * software distributed under the License is distributed on an
+- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+- * KIND, either express or implied. See the License for the
+- * specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-#include <iostream>
+-
+-#include <thrift/protocol/TBinaryProtocol.h>
+-#include <thrift/transport/TSocket.h>
+-#include <thrift/transport/TTransportUtils.h>
+-
+-#include "../gen-cpp/Calculator.h"
+-
+-using namespace std;
+-using namespace apache::thrift;
+-using namespace apache::thrift::protocol;
+-using namespace apache::thrift::transport;
+-
+-using namespace tutorial;
+-using namespace shared;
+-
+-int main() {
+-  boost::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
+-  boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
+-  boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
+-  CalculatorClient client(protocol);
+-
+-  try {
+-    transport->open();
+-
+-    client.ping();
+-    cout << "ping()" << endl;
+-
+-    cout << "1 + 1 = " << client.add(1, 1) << endl;
+-
+-    Work work;
+-    work.op = Operation::DIVIDE;
+-    work.num1 = 1;
+-    work.num2 = 0;
+-
+-    try {
+-      client.calculate(1, work);
+-      cout << "Whoa? We can divide by zero!" << endl;
+-    } catch (InvalidOperation& io) {
+-      cout << "InvalidOperation: " << io.why << endl;
+-      // or using generated operator<<: cout << io << endl;
+-      // or by using std::exception native method what(): cout << io.what() << endl;
+-    }
+-
+-    work.op = Operation::SUBTRACT;
+-    work.num1 = 15;
+-    work.num2 = 10;
+-    int32_t diff = client.calculate(1, work);
+-    cout << "15 - 10 = " << diff << endl;
+-
+-    // Note that C++ uses return by reference for complex types to avoid
+-    // costly copy construction
+-    SharedStruct ss;
+-    client.getStruct(ss, 1);
+-    cout << "Received log: " << ss << endl;
+-
+-    transport->close();
+-  } catch (TException& tx) {
+-    cout << "ERROR: " << tx.what() << endl;
+-  }
+-}
+diff --git a/tutorial/cpp/CppServer.cpp b/tutorial/cpp/CppServer.cpp
+deleted file mode 100644
+index eafffa9..0000000
+--- a/tutorial/cpp/CppServer.cpp
++++ /dev/null
+@@ -1,181 +0,0 @@
+-/*
+- * Licensed to the Apache Software Foundation (ASF) under one
+- * or more contributor license agreements. See the NOTICE file
+- * distributed with this work for additional information
+- * regarding copyright ownership. The ASF licenses this file
+- * to you under the Apache License, Version 2.0 (the
+- * "License"); you may not use this file except in compliance
+- * with the License. You may obtain a copy of the License at
+- *
+- *   http://www.apache.org/licenses/LICENSE-2.0
+- *
+- * Unless required by applicable law or agreed to in writing,
+- * software distributed under the License is distributed on an
+- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+- * KIND, either express or implied. See the License for the
+- * specific language governing permissions and limitations
+- * under the License.
+- */
+-
+-#include <thrift/concurrency/ThreadManager.h>
+-#include <thrift/concurrency/PlatformThreadFactory.h>
+-#include <thrift/protocol/TBinaryProtocol.h>
+-#include <thrift/server/TSimpleServer.h>
+-#include <thrift/server/TThreadPoolServer.h>
+-#include <thrift/server/TThreadedServer.h>
+-#include <thrift/transport/TServerSocket.h>
+-#include <thrift/transport/TSocket.h>
+-#include <thrift/transport/TTransportUtils.h>
+-#include <thrift/TToString.h>
+-
+-#include <boost/make_shared.hpp>
+-
+-#include <iostream>
+-#include <stdexcept>
+-#include <sstream>
+-
+-#include "../gen-cpp/Calculator.h"
+-
+-using namespace std;
+-using namespace apache::thrift;
+-using namespace apache::thrift::concurrency;
+-using namespace apache::thrift::protocol;
+-using namespace apache::thrift::transport;
+-using namespace apache::thrift::server;
+-
+-using namespace tutorial;
+-using namespace shared;
+-
+-class CalculatorHandler : public CalculatorIf {
+-public:
+-  CalculatorHandler() {}
+-
+-  void ping() { cout << "ping()" << endl; }
+-
+-  int32_t add(const int32_t n1, const int32_t n2) {
+-    cout << "add(" << n1 << ", " << n2 << ")" << endl;
+-    return n1 + n2;
+-  }
+-
+-  int32_t calculate(const int32_t logid, const Work& work) {
+-    cout << "calculate(" << logid << ", " << work << ")" << endl;
+-    int32_t val;
+-
+-    switch (work.op) {
+-    case Operation::ADD:
+-      val = work.num1 + work.num2;
+-      break;
+-    case Operation::SUBTRACT:
+-      val = work.num1 - work.num2;
+-      break;
+-    case Operation::MULTIPLY:
+-      val = work.num1 * work.num2;
+-      break;
+-    case Operation::DIVIDE:
+-      if (work.num2 == 0) {
+-        InvalidOperation io;
+-        io.whatOp = work.op;
+-        io.why = "Cannot divide by 0";
+-        throw io;
+-      }
+-      val = work.num1 / work.num2;
+-      break;
+-    default:
+-      InvalidOperation io;
+-      io.whatOp = work.op;
+-      io.why = "Invalid Operation";
+-      throw io;
+-    }
+-
+-    SharedStruct ss;
+-    ss.key = logid;
+-    ss.value = to_string(val);
+-
+-    log[logid] = ss;
+-
+-    return val;
+-  }
+-
+-  void getStruct(SharedStruct& ret, const int32_t logid) {
+-    cout << "getStruct(" << logid << ")" << endl;
+-    ret = log[logid];
+-  }
+-
+-  void zip() { cout << "zip()" << endl; }
+-
+-protected:
+-  map<int32_t, SharedStruct> log;
+-};
+-
+-/*
+-  CalculatorIfFactory is code generated.
+-  CalculatorCloneFactory is useful for getting access to the server side of the
+-  transport.  It is also useful for making per-connection state.  Without this
+-  CloneFactory, all connections will end up sharing the same handler instance.
+-*/
+-class CalculatorCloneFactory : virtual public CalculatorIfFactory {
+- public:
+-  virtual ~CalculatorCloneFactory() {}
+-  virtual CalculatorIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo)
+-  {
+-    boost::shared_ptr<TSocket> sock = boost::dynamic_pointer_cast<TSocket>(connInfo.transport);
+-    cout << "Incoming connection\n";
+-    cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
+-    cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
+-    cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
+-    cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
+-    return new CalculatorHandler;
+-  }
+-  virtual void releaseHandler( ::shared::SharedServiceIf* handler) {
+-    delete handler;
+-  }
+-};
+-
+-int main() {
+-  TThreadedServer server(
+-    boost::make_shared<CalculatorProcessorFactory>(boost::make_shared<CalculatorCloneFactory>()),
+-    boost::make_shared<TServerSocket>(9090), //port
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>());
+-
+-  /*
+-  // if you don't need per-connection state, do the following instead
+-  TThreadedServer server(
+-    boost::make_shared<CalculatorProcessor>(boost::make_shared<CalculatorHandler>()),
+-    boost::make_shared<TServerSocket>(9090), //port
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>());
+-  */
+-
+-  /**
+-   * Here are some alternate server types...
+-
+-  // This server only allows one connection at a time, but spawns no threads
+-  TSimpleServer server(
+-    boost::make_shared<CalculatorProcessor>(boost::make_shared<CalculatorHandler>()),
+-    boost::make_shared<TServerSocket>(9090),
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>());
+-
+-  const int workerCount = 4;
+-
+-  boost::shared_ptr<ThreadManager> threadManager =
+-    ThreadManager::newSimpleThreadManager(workerCount);
+-  threadManager->threadFactory(
+-    boost::make_shared<PlatformThreadFactory>());
+-  threadManager->start();
+-
+-  // This server allows "workerCount" connection at a time, and reuses threads
+-  TThreadPoolServer server(
+-    boost::make_shared<CalculatorProcessorFactory>(boost::make_shared<CalculatorCloneFactory>()),
+-    boost::make_shared<TServerSocket>(9090),
+-    boost::make_shared<TBufferedTransportFactory>(),
+-    boost::make_shared<TBinaryProtocolFactory>(),
+-    threadManager);
+-  */
+-
+-  cout << "Starting the server..." << endl;
+-  server.serve();
+-  cout << "Done." << endl;
+-  return 0;
+-}
+diff --git a/tutorial/cpp/GriftClient.cpp b/tutorial/cpp/GriftClient.cpp
+new file mode 100644
+index 0000000..647a683
+--- /dev/null
++++ b/tutorial/cpp/GriftClient.cpp
+@@ -0,0 +1,93 @@
++/*
++ *
++ * 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 <iostream>
++#include <memory>
++#include <string>
++
++#include <grpc++/grpc++.h>
++
++#include "gen-cpp/Greeter.grpc.thrift.h"
++
++using grpc::Channel;
++using grpc::ClientContext;
++using grpc::Status;
++using test::Greeter;
++
++class GreeterClient {
++ public:
++  GreeterClient(std::shared_ptr<Channel> channel)
++      : stub_(Greeter::NewStub(channel)) {}
++
++  // 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.
++    Greeter::SayHelloReq req;
++    req.request.name = user;
++
++    // Container for the data we expect from the server.
++    Greeter::SayHelloResp reply;
++
++    // Context for the client. It could be used to convey extra information to
++    // the server and/or tweak certain RPC behaviors.
++    ClientContext context;
++
++    // The actual RPC.
++    Status status = stub_->SayHello(&context, req, &reply);
++
++    // Act upon its status.
++    if (status.ok()) {
++      return reply.success.message;
++    } else {
++      return "RPC failed";
++    }
++  }
++
++ private:
++  std::unique_ptr<Greeter::Stub> stub_;
++};
++
++int main() {
++  // Instantiate the client. It requires a channel, out of which the actual RPCs
++  // are created. This channel models a connection to an endpoint (in this case,
++  // localhost at port 50051). We indicate that the channel isn't authenticated
++  // (use of InsecureChannelCredentials()).
++  GreeterClient greeter(grpc::CreateChannel(
++      "localhost:50051", grpc::InsecureChannelCredentials()));
++  std::string user("world");
++  std::string reply = greeter.SayHello(user);
++  std::cout << "Greeter received: " << reply << std::endl;
++
++  return 0;
++}
+diff --git a/tutorial/cpp/GriftServer.cpp b/tutorial/cpp/GriftServer.cpp
+new file mode 100644
+index 0000000..7c01606
+--- /dev/null
++++ b/tutorial/cpp/GriftServer.cpp
+@@ -0,0 +1,93 @@
++/*
++ *
++ * 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 <iostream>
++#include <memory>
++#include <string>
++
++#include <grpc++/grpc++.h>
++
++#include "gen-cpp/Greeter.grpc.thrift.h"
++#include <grpc++/server_builder.h>
++
++using grpc::Server;
++using grpc::ServerBuilder;
++using grpc::ServerContext;
++using grpc::Status;
++using test::Greeter;
++
++// Logic and data behind the server's behavior.
++class GreeterServiceImpl final : public Greeter::Service {
++ public:
++  ~GreeterServiceImpl() {
++    // shutdown server
++    server->Shutdown();
++  }
++
++  Status SayHello(ServerContext* context,const Greeter::SayHelloReq* request,
++                  Greeter::SayHelloResp* reply) override {
++    std::string prefix("Hello ");
++
++    reply->success.message = prefix + request->request.name;
++
++    return Status::OK;
++  }
++
++  void RunServer() {
++    std::string server_address("0.0.0.0:50051");
++
++    ServerBuilder builder;
++    // Listen on the given address without any authentication mechanism.
++    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
++    // Register "service" as the instance through which we'll communicate with
++    // clients. In this case it corresponds to an *synchronous* service.
++    builder.RegisterService(this);
++    // Finally assemble the server.
++    server = builder.BuildAndStart();
++    std::cout << "Server listening on " << server_address << std::endl;
++
++    // Wait for the server to shutdown. Note that some other thread must be
++    // responsible for shutting down the server for this call to ever return.
++    server->Wait();
++  }
++
++ private:
++  std::unique_ptr<Server> server;
++};
++
++int main() {
++  GreeterServiceImpl service;
++  service.RunServer();
++
++  return 0;
++}
+diff --git a/tutorial/cpp/Makefile.am b/tutorial/cpp/Makefile.am
+index 184a69d..6f91e28 100755
+--- a/tutorial/cpp/Makefile.am
++++ b/tutorial/cpp/Makefile.am
+@@ -18,44 +18,38 @@
+ #
+ AUTOMAKE_OPTIONS = subdir-objects serial-tests
+ 
+-BUILT_SOURCES = gen-cpp/shared_types.cpp \
+-                gen-cpp/tutorial_types.cpp
++BUILT_SOURCES = gen-cpp/test_types.cpp
+ 
+-noinst_LTLIBRARIES = libtutorialgencpp.la
+-nodist_libtutorialgencpp_la_SOURCES = \
+-	gen-cpp/Calculator.cpp \
+-	gen-cpp/Calculator.h \
+-	gen-cpp/SharedService.cpp \
+-	gen-cpp/SharedService.h \
+-	gen-cpp/shared_constants.cpp \
+-	gen-cpp/shared_constants.h \
+-	gen-cpp/shared_types.cpp \
+-	gen-cpp/shared_types.h \
+-	gen-cpp/tutorial_constants.cpp \
+-	gen-cpp/tutorial_constants.h \
+-	gen-cpp/tutorial_types.cpp \
+-	gen-cpp/tutorial_types.h
++#noinst_LTLIBRARIES = libtutorialgencpp.la
++noinst_LTLIBRARIES = libtestgencpp.la
++nodist_libtestgencpp_la_SOURCES = \
++	gen-cpp/Greeter.grpc.thrift.cpp \
++	gen-cpp/Greeter.grpc.thrift.h \
++	gen-cpp/test_constants.cpp \
++	gen-cpp/test_constants.h \
++	gen-cpp/test_types.cpp \
++	gen-cpp/test_types.h
+ 
+ 
+ 
+-libtutorialgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
++libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+ 
+ noinst_PROGRAMS = \
+-	TutorialServer \
+-	TutorialClient
++	TestServer \
++	TestClient
+ 
+-TutorialServer_SOURCES = \
+-	CppServer.cpp
++TestServer_SOURCES = \
++	GriftServer.cpp
+ 
+-TutorialServer_LDADD = \
+-	libtutorialgencpp.la \
++TestServer_LDADD = \
++	libtestgencpp.la \
+ 	$(top_builddir)/lib/cpp/libthrift.la
+ 
+-TutorialClient_SOURCES = \
+-	CppClient.cpp
++TestClient_SOURCES = \
++	GriftClient.cpp
+ 
+-TutorialClient_LDADD = \
+-	libtutorialgencpp.la \
++TestClient_LDADD = \
++	libtestgencpp.la \
+ 	$(top_builddir)/lib/cpp/libthrift.la
+ 
+ #
+@@ -63,26 +57,26 @@ TutorialClient_LDADD = \
+ #
+ THRIFT = $(top_builddir)/compiler/cpp/thrift
+ 
+-gen-cpp/Calculator.cpp gen-cpp/SharedService.cpp gen-cpp/shared_constants.cpp gen-cpp/shared_types.cpp gen-cpp/tutorial_constants.cpp gen-cpp/tutorial_types.cpp: $(top_srcdir)/tutorial/tutorial.thrift
++gen-cpp/Greeter.grpc.thrift.cpp gen-cpp/test_constants.cpp gen-cpp/test_types.cpp: $(top_srcdir)/tutorial/cpp/test.thrift
+ 	$(THRIFT) --gen cpp -r $<
+ 
+ AM_CPPFLAGS = $(BOOST_CPPFLAGS) $(LIBEVENT_CPPFLAGS) -I$(top_srcdir)/lib/cpp/src -Igen-cpp
+ AM_CXXFLAGS = -Wall -Wextra -pedantic
+-AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS)
++AM_LDFLAGS = $(BOOST_LDFLAGS) $(LIBEVENT_LDFLAGS) `pkg-config --libs grpc++ grpc` -lpthread -ldl -lgrpc
+ 
+ clean-local:
+-	$(RM) gen-cpp/*
++	$(RM) -r gen-cpp
+ 
+-tutorialserver: all
+-	./TutorialServer
++testserver: all
++	./TestServer
+ 
+-tutorialclient: all
+-	./TutorialClient
++testclient: all
++	./TestClient
+ 
+ style-local:
+ 	$(CPPSTYLE_CMD)
+ 
+ EXTRA_DIST = \
+ 	CMakeLists.txt \
+-	CppClient.cpp \
+-	CppServer.cpp
++	GriftClient.cpp \
++	GriftServer.cpp
+diff --git a/tutorial/cpp/test.thrift b/tutorial/cpp/test.thrift
+new file mode 100644
+index 0000000..de3c9a4
+--- /dev/null
++++ b/tutorial/cpp/test.thrift
+@@ -0,0 +1,13 @@
++namespace cpp test
++
++struct HelloRequest {
++	1:string name
++}
++
++struct HelloResponse {
++	1:string message
++}
++
++service Greeter {
++	HelloResponse SayHello(1:HelloRequest request);
++}
+\ No newline at end of file
+-- 
+2.8.0.rc3.226.g39d4020
+
+
+From 3e4d75a2e2c474ee7700e7c9acaf89fdb768bedc Mon Sep 17 00:00:00 2001
+From: chedeti <chedeti@google.com>
+Date: Sun, 31 Jul 2016 16:23:53 -0700
+Subject: [PATCH 3/3] grpc java plugins generator
+
+for examples refer to https://github.com/grpc/grpc-java/tree/master/examples/thrift
+---
+ compiler/cpp/src/generate/t_java_generator.cc | 906 +++++++++++++++++++++++++-
+ tutorial/Makefile.am                          |   8 +-
+ 2 files changed, 887 insertions(+), 27 deletions(-)
+
+diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
+index 2db8cb8..8b28fe2 100644
+--- a/compiler/cpp/src/generate/t_java_generator.cc
++++ b/compiler/cpp/src/generate/t_java_generator.cc
+@@ -97,10 +97,10 @@ public:
+         } else if(iter->second.compare("suppress") == 0) {
+           suppress_generated_annotations_ = true;
+         } else {
+-          throw "unknown option java:" + iter->first + "=" + iter->second; 
++          throw "unknown option java:" + iter->first + "=" + iter->second;
+         }
+       } else {
+-        throw "unknown option java:" + iter->first; 
++        throw "unknown option java:" + iter->first;
+       }
+     }
+ 
+@@ -195,6 +195,17 @@ public:
+   void generate_service_async_server(t_service* tservice);
+   void generate_process_function(t_service* tservice, t_function* tfunction);
+   void generate_process_async_function(t_service* tservice, t_function* tfunction);
++  void generate_service_impl_base(t_service* tservice);
++  void generate_method_descriptors(t_service* tservice);
++  void generate_stub(t_service* tservice);
++  void generate_blocking_stub(t_service* tservice);
++  void generate_future_stub(t_service* tservice);
++  void generate_method_ids(t_service* tservice);
++  void generate_method_handlers(t_service* tservice);
++  void generate_service_descriptors(t_service* tservice);
++  void generate_service_builder(t_service* tservice);
++  void generate_arg_ids(t_service* tservice);
++  void generate_message_factory(t_service* tservice);
+ 
+   void generate_java_union(t_struct* tstruct);
+   void generate_union_constructor(ofstream& out, t_struct* tstruct);
+@@ -307,6 +318,8 @@ public:
+   std::string java_package();
+   std::string java_type_imports();
+   std::string java_suppressions();
++  std::string grpc_imports();
++  std::string import_extended_service(t_service* tservice);
+   std::string type_name(t_type* ttype,
+                         bool in_container = false,
+                         bool in_init = false,
+@@ -368,7 +381,7 @@ private:
+   bool use_option_type_;
+   bool undated_generated_annotations_;
+   bool suppress_generated_annotations_;
+-  
++
+ };
+ 
+ /**
+@@ -456,6 +469,35 @@ string t_java_generator::java_suppressions() {
+   return "@SuppressWarnings({\"cast\", \"rawtypes\", \"serial\", \"unchecked\", \"unused\"})\n";
+ }
+ 
++string t_java_generator::grpc_imports() {
++  return
++    string() +
++    "import static io.grpc.stub.ClientCalls.asyncUnaryCall;\n" +
++    "import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.blockingUnaryCall;\n" +
++    "import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n" +
++    "import static io.grpc.stub.ClientCalls.futureUnaryCall;\n" +
++    "import static io.grpc.MethodDescriptor.generateFullMethodName;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncUnaryCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n" +
++    "import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n" +
++    "import io.grpc.thrift.ThriftUtils;\n\n";
++}
++
++string t_java_generator::import_extended_service(t_service* tservice) {
++  if (!tservice) {
++    return string() + "\n";
++  }
++  string ns = tservice->get_program()->get_namespace("java");
++  string extend_service_name = tservice->get_name() + "Grpc";
++  return string() + "import " + ns + "." + extend_service_name + ";\n\n";
++}
++
+ /**
+  * Nothing in Java
+  */
+@@ -2772,25 +2814,51 @@ void t_java_generator::generate_field_value_meta_data(std::ofstream& out, t_type
+  */
+ void t_java_generator::generate_service(t_service* tservice) {
+   // Make output file
+-  string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + ".java";
++  string f_service_name = package_dir_ + "/" + make_valid_java_filename(service_name_) + "Grpc.java";
+   f_service_.open(f_service_name.c_str());
+ 
+-  f_service_ << autogen_comment() << java_package() << java_type_imports() << java_suppressions();
++  f_service_ <<
++      autogen_comment() <<
++      java_package() <<
++      java_type_imports() <<
++      grpc_imports() <<
++      import_extended_service(tservice->get_extends());
++      java_suppressions();
++
++  f_service_ <<
++    "public class " << service_name_ << "Grpc {" << endl <<
++    endl;
+ 
+-  if (!suppress_generated_annotations_) {
+-    generate_javax_generated_annotation(f_service_);
+-  }
+-  f_service_ << "public class " << service_name_ << " {" << endl << endl;
+   indent_up();
+ 
++  // generate constructor
++  f_service_ <<
++    indent() << "private " << service_name_ <<
++    "Grpc() {}" << endl << endl;
++
++  f_service_ <<
++    indent() << "public static final String SERVICE_NAME = " <<
++    "\"" << package_name_ << "." << service_name_ << "\";" << endl << endl;
++
+   // Generate the three main parts of the service
+   generate_service_interface(tservice);
+-  generate_service_async_interface(tservice);
+-  generate_service_client(tservice);
+-  generate_service_async_client(tservice);
+-  generate_service_server(tservice);
+-  generate_service_async_server(tservice);
++  generate_arg_ids(tservice);
++  generate_message_factory(tservice);
++  generate_service_impl_base(tservice);
++  //generate_service_async_interface(tservice);
++  //generate_service_client(tservice);
++  //generate_service_async_client(tservice);
++  //generate_service_server(tservice);
++  //generate_service_async_server(tservice);
+   generate_service_helpers(tservice);
++  generate_method_descriptors(tservice);
++  generate_stub(tservice);
++  generate_blocking_stub(tservice);
++  generate_future_stub(tservice);
++  generate_method_ids(tservice);
++  generate_method_handlers(tservice);
++  generate_service_descriptors(tservice);
++  generate_service_builder(tservice);
+ 
+   indent_down();
+   f_service_ << "}" << endl;
+@@ -2805,24 +2873,820 @@ void t_java_generator::generate_service(t_service* tservice) {
+ void t_java_generator::generate_service_interface(t_service* tservice) {
+   string extends = "";
+   string extends_iface = "";
+-  if (tservice->get_extends() != NULL) {
+-    extends = type_name(tservice->get_extends());
+-    extends_iface = " extends " + extends + ".Iface";
+-  }
+ 
+   generate_java_doc(f_service_, tservice);
+-  f_service_ << indent() << "public interface Iface" << extends_iface << " {" << endl << endl;
++  f_service_ << indent() <<
++    "@java.lang.Deprecated public static interface " << service_name_;
++
++  if (tservice->get_extends()) {
++    f_service_ << " extends " << tservice->get_extends()->get_name() + "Grpc." <<
++      tservice->get_extends()->get_name() << endl;
++  }
++  f_service_ << " {" << endl;
++
++  indent_up();
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    //generate_java_doc(f_service_, *f_iter);
++    f_service_ <<
++      indent() << "public void " << (*f_iter)->get_name() << "(" << (*f_iter)->get_name() <<
++      "_args request," << endl <<
++      indent() << "    io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() <<
++      "_result> responseObserver);" << endl << endl;
++  }
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_arg_ids(t_service* tservice) {
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  int i=0;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ << indent() <<
++      "private static final int ARG_IN_METHOD_" <<
++      (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++    f_service_ << indent() <<
++      "private static final int ARG_OUT_METHOD_" <<
++      (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++  }
++  f_service_ << endl;
++
++  if (tservice->get_extends()) {
++    f_service_ << indent() << "// ARG IDs for extended service" << endl;
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ << indent() <<
++        "private static final int ARG_IN_METHOD_" <<
++        (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++      f_service_ << indent() <<
++        "private static final int ARG_OUT_METHOD_" <<
++        (*f_iter)->get_name() << " = " << ++i << ";" << endl;
++    }
++    f_service_ << endl;
++  }
++}
++
++void t_java_generator::generate_message_factory(t_service* tservice) {
++  f_service_ << indent() <<
++    "private static final class ThriftMessageFactory<T extends " <<
++    "org.apache.thrift.TBase<T,?>>" << endl << indent() <<
++    "    implements io.grpc.thrift.MessageFactory<T> {" << endl;
++  indent_up();
++  f_service_ << indent() <<
++      "private final int id;" << endl << endl;
++  f_service_ << endl;
++
++  f_service_ << indent() <<
++    "ThriftMessageFactory(int id) {" << endl <<
++    indent() << "  this.id = id;" << endl <<
++    indent() << "}" << endl;
++
++  f_service_ << indent() <<
++    "@java.lang.Override" << endl <<
++    indent() << "public T newInstance() {" << endl;
++  indent_up();
++
++  f_service_ << indent() <<
++    "Object o;" << endl <<
++    indent() << "switch (id) {" << endl;
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ << indent() <<
++      "case ARG_IN_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++      indent() << "  o = new " << (*f_iter)->get_name() << "_args();" <<
++      endl << indent() << "  break;" << endl;
++    f_service_ << indent() <<
++      "case ARG_OUT_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++      indent() << " o = new " << (*f_iter)->get_name() << "_result();" <<
++      endl << indent() << "  break;" << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for (f_iter = functions.begin(); f_iter!= functions.end(); ++f_iter) {
++      f_service_ << indent() <<
++        "case ARG_IN_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++        indent() << "  o = new " << extend_service_name << "." << (*f_iter)->get_name() << "_args();" <<
++        endl << indent() << "  break;" << endl;
++      f_service_ << indent() <<
++        "case ARG_OUT_METHOD_" << (*f_iter)->get_name() << ":" << endl <<
++        indent() << " o = new " << extend_service_name << "." << (*f_iter)->get_name() << "_result();" <<
++        endl << indent() << "  break;" << endl;
++    }
++  }
++
++  f_service_  << indent() <<
++    "default:" << endl << indent() <<
++    "  throw new AssertionError();" << endl << indent() <<
++    "}" << endl;
++
++  f_service_ << indent() <<
++    "@java.lang.SuppressWarnings(\"unchecked\")" << endl <<
++    indent() << "T t = (T) o;" << endl << indent() <<
++    "return t;" << endl;
++
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl;
++
++  indent_down();
++  f_service_ << indent() << "}" << endl;
++}
++
++void t_java_generator::generate_service_impl_base(t_service* tservice) {
++  f_service_ <<
++    indent() << "public static abstract class " << service_name_ <<
++    "ImplBase implements " << service_name_ << ", io.grpc.BindableService {" << endl;
++  indent_up();
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public void " << (*f_iter)->get_name() << "(" << (*f_iter)->get_name() <<
++      "_args request, " << endl <<
++      indent() << "    io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() <<
++      "_result> responseObserver) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "asyncUnimplementedUnaryCall(METHOD_" << (*f_iter)->get_name() <<
++      ", responseObserver);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc" ;
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public void " << (*f_iter)->get_name() << "(" <<
++        extend_service_name << "." << (*f_iter)->get_name() <<
++        "_args request, " << endl <<
++        indent() << "    io.grpc.stub.StreamObserver<" << extend_service_name
++        << "." << (*f_iter)->get_name() << "_result> responseObserver) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "asyncUnimplementedUnaryCall(METHOD_" << (*f_iter)->get_name() <<
++        ", responseObserver);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++
++  f_service_ <<
++    indent() << "@java.lang.Override" <<
++    " public io.grpc.ServerServiceDefinition bindService() {" << endl;
+   indent_up();
++  f_service_ <<
++    indent() << "return " << service_name_ << "Grpc.bindService(this);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Abstract Service
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static abstract class Abstract" << service_name_ <<
++    " extends " << service_name_ << "ImplBase {}" << endl << endl;
++}
++
++void t_java_generator::generate_method_descriptors(t_service* tservice) {
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for( f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "public static final io.grpc.MethodDescriptor<" <<
++      (*f_iter)->get_name() << "_args," << endl <<
++      indent() << "    " << (*f_iter)->get_name() << "_result> METHOD_" << (*f_iter)->get_name() <<
++      " = " << endl << indent() << "    io.grpc.MethodDescriptor.create(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    io.grpc.MethodDescriptor.MethodType.UNARY," << endl <<
++      indent() << "    generateFullMethodName(" << "\"" << package_name_ << "." <<
++      service_name_ << "\" , \"" << (*f_iter)->get_name() << "\")," << endl <<
++      indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++      indent() << "    new ThriftMessageFactory<" << (*f_iter)->get_name() <<
++      "_args>( ARG_IN_METHOD_" << (*f_iter)->get_name() << "))," << endl <<
++      indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++      indent() << "    new ThriftMessageFactory<" << (*f_iter)->get_name() <<
++      "_result>( ARG_OUT_METHOD_" << (*f_iter)->get_name() << ")));" << endl << endl;
++    indent_down();
++  }
++
++  if(tservice->get_extends()) {
++    t_service* extends_service = tservice->get_extends();
++    functions = extends_service->get_functions();
++    string extend_service_name = extends_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "public static final io.grpc.MethodDescriptor<" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_args," << endl <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() << "_result> METHOD_"
++        << (*f_iter)->get_name() << " = " << endl << indent() <<
++        "    io.grpc.MethodDescriptor.create(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    io.grpc.MethodDescriptor.MethodType.UNARY," << endl <<
++        indent() << "    generateFullMethodName(" << "\"" << package_name_ << "." <<
++        service_name_ << "\" , \"" << (*f_iter)->get_name() << "\")," << endl <<
++        indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++        indent() << "    new ThriftMessageFactory<" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_args>( ARG_IN_METHOD_" << (*f_iter)->get_name() << "))," << endl <<
++        indent() << "    io.grpc.thrift.ThriftUtils.marshaller(" << endl <<
++        indent() << "    new ThriftMessageFactory<" << extend_service_name << "." << (*f_iter)->get_name() <<
++        "_result>( ARG_OUT_METHOD_" << (*f_iter)->get_name() << ")));" << endl << endl;
++      indent_down();
++    }
++  }
++}
++
++void t_java_generator::generate_stub(t_service* tservice) {
++  f_service_ <<
++    indent() <<
++    "public static " << service_name_ <<
++    "Stub newStub(io.grpc.Channel channel) {" <<
++    endl;
++
++  indent_up();
++  f_service_ <<
++    indent() <<
++    "return new " << service_name_ << "Stub(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Stub impl
++
++  f_service_ <<
++    indent() << "public static class " <<
++    service_name_ << "Stub extends io.grpc.stub.AbstractStub<" <<
++    service_name_ << "Stub>" << endl <<
++    indent() << "    implements " << service_name_ << "{" << endl;
++  indent_up();
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "Stub(io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "Stub(io.grpc.Channel channel, " << endl <<
++    indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "protected " << service_name_ << "Stub build(io.grpc.Channel channel, " <<
++    endl << indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "Stub(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public void " << (*f_iter)->get_name() << "(" <<
++      (*f_iter)->get_name() << "_args request," << endl << indent() <<
++      "    io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() <<
++      "_result> responseObserver) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "asyncUnaryCall(" << endl <<
++      indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++      ", getCallOptions()), request, responseObserver);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public void " << (*f_iter)->get_name() << "(" <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_args request,"
++        << endl << indent() << "    io.grpc.stub.StreamObserver<" <<
++        extend_service_name << "." << (*f_iter)->get_name() <<
++        "_result> responseObserver) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "asyncUnaryCall(" << endl <<
++        indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++        ", getCallOptions()), request, responseObserver);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_blocking_stub(t_service* tservice) {
++  f_service_ <<
++    indent() << "public static " << service_name_ <<
++    "BlockingStub newBlockingStub(" << endl <<
++    indent() << "    io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "BlockingStub(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Blocking Client
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static interface " << service_name_ <<
++    "BlockingClient " ;
++  
++  if (tservice->get_extends()) {
++    string extend_service_name = tservice->get_extends()->get_name();
++    f_service_ << endl << indent() << "    extends " << extend_service_name << "Grpc." <<
++        extend_service_name << "BlockingClient " ;
++  }
++
++  f_service_ << "{" << endl;
++
++  indent_up();
++
+   vector<t_function*> functions = tservice->get_functions();
+   vector<t_function*>::iterator f_iter;
+   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+-    generate_java_doc(f_service_, *f_iter);
+-    indent(f_service_) << "public " << function_signature(*f_iter) << ";" << endl << endl;
++    f_service_ <<
++      indent() << "public " << (*f_iter)->get_name() << "_result " <<
++      (*f_iter)->get_name() << "(" << (*f_iter)->get_name() << "_args request);" << endl << endl;
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Blocking Stub impl
++
++  f_service_ <<
++    indent() << "public static class " <<
++    service_name_ << "BlockingStub extends io.grpc.stub.AbstractStub<" <<
++    service_name_ << "BlockingStub>" << endl <<
++    indent() << "    implements " << service_name_ << "BlockingClient {";
++
++  indent_up();
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "BlockingStub(io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "BlockingStub(io.grpc.Channel channel, " << endl <<
++    indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "protected " << service_name_ << "BlockingStub build(io.grpc.Channel channel, " <<
++    endl << indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "BlockingStub(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public " << (*f_iter)->get_name() << "_result " << (*f_iter)->get_name() << "(" <<
++      (*f_iter)->get_name() << "_args request) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "return blockingUnaryCall(" << endl <<
++      indent() << "    getChannel(), METHOD_" << (*f_iter)->get_name() <<
++      ", getCallOptions(), request);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public " << extend_service_name << "." << (*f_iter)->get_name() <<
++        "_result " << (*f_iter)->get_name() << "(" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_args request) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "return blockingUnaryCall(" << endl <<
++        indent() << "    getChannel(), METHOD_" << (*f_iter)->get_name() <<
++        ", getCallOptions(), request);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_future_stub(t_service* tservice) {
++  f_service_ <<
++    indent() << "public static " << service_name_ <<
++    "FutureStub newFutureStub(" << endl <<
++    indent() << "    io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "FutureStub(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Future Client
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static interface " << service_name_ <<
++    "FutureClient " ;
++
++  if (tservice->get_extends()) {
++    string extend_service_name = tservice->get_extends()->get_name();
++    f_service_ << endl << indent() << "    extends " << extend_service_name << "Grpc." <<
++        extend_service_name << "FutureClient " ; 
++  }
++  f_service_ << "{" << endl;
++
++  indent_up();
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++      (*f_iter)->get_name() << "_result> " << (*f_iter)->get_name() << "(" << endl <<
++      indent() << "    " << (*f_iter)->get_name() << "_args request);" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_result> " <<
++        (*f_iter)->get_name() << "(" << endl <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() <<
++        "_args request);" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // generate Stub impl
++
++  f_service_ <<
++    indent() << "public static class " <<
++    service_name_ << "FutureStub extends io.grpc.stub.AbstractStub<" <<
++    service_name_ << "FutureStub>" << endl <<
++    indent() << "    implements " << service_name_ << "FutureClient {" << endl;
++  indent_up();
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "FutureStub(io.grpc.Channel channel) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "private " << service_name_ << "FutureStub(io.grpc.Channel channel, " << endl <<
++    indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "super(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "protected " << service_name_ << "FutureStub build(io.grpc.Channel channel, " <<
++    endl << indent() << "    io.grpc.CallOptions callOptions) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new " << service_name_ << "FutureStub(channel, callOptions);" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  functions = tservice->get_functions();
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "@java.lang.Override" << endl <<
++      indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++      (*f_iter)->get_name() << "_result> " << (*f_iter)->get_name() << "(" <<
++      endl << indent() << "    " << (*f_iter)->get_name() << "_args request) {" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "return futureUnaryCall(" << endl <<
++      indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++      ", getCallOptions()), request);" << endl;
++    indent_down();
++    f_service_ <<
++      indent() << "}" << endl << endl;
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "@java.lang.Override" << endl <<
++        indent() << "public com.google.common.util.concurrent.ListenableFuture<" <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_result> " <<
++        (*f_iter)->get_name() << "(" << endl << indent() << "    " <<
++        extend_service_name << "." << (*f_iter)->get_name() << "_args request) {" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "return futureUnaryCall(" << endl <<
++        indent() << "    getChannel().newCall(METHOD_" << (*f_iter)->get_name() <<
++        ", getCallOptions()), request);" << endl;
++      indent_down();
++      f_service_ <<
++        indent() << "}" << endl << endl;
++    }
++  }
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_method_ids(t_service* tservice) {
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  int i=0;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter, ++i) {
++    f_service_ <<
++      indent() << "private static final int METHODID_" <<
++      (*f_iter)->get_name() << " = " << i << ";" << endl;
++  }
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter, ++i) {
++      f_service_ <<
++        indent() << "private static final int METHODID_" <<
++        (*f_iter)->get_name() << " = " << i << ";" << endl;
++    }
++  }
++  f_service_ << endl;
++}
++
++void t_java_generator::generate_method_handlers(t_service* tservice) {
++  f_service_ <<
++    indent() << "private static class MethodHandlers<Req, Resp> implements" <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>," <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>," <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>," <<
++    endl << indent() << "    io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {" <<
++    endl;
++  indent_up();
++  f_service_ <<
++    indent() << "private final " << service_name_ << " serviceImpl;" << endl <<
++    indent() << "private final int methodId;" << endl << endl;
++
++  f_service_ <<
++    indent() << "public MethodHandlers(" << service_name_ << " serviceImpl, int " <<
++    "methodId) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "this.serviceImpl = serviceImpl;" << endl <<
++    indent() << "this.methodId = methodId;" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // invoke
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "@java.lang.SuppressWarnings(\"unchecked\")" << endl <<
++    indent() << "public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {" <<
++    endl;
++  indent_up();
++  f_service_ <<
++    indent() << "switch (methodId) {" << endl;
++  indent_up();
++
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "case METHODID_" << (*f_iter)->get_name() << ":" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "serviceImpl." << (*f_iter)->get_name() << "((" << (*f_iter)->get_name() <<
++      "_args) request," << endl <<
++      indent() << "    (io.grpc.stub.StreamObserver<" << (*f_iter)->get_name() << "_result>)" <<
++      " responseObserver);" << endl <<
++      indent() << "break;" << endl << endl;
++    indent_down();
++  }
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "case METHODID_" << (*f_iter)->get_name() << ":" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "serviceImpl." << (*f_iter)->get_name() << "((" << extend_service_name <<
++        "." << (*f_iter)->get_name() << "_args) request," << endl <<
++        indent() << "    (io.grpc.stub.StreamObserver<" << extend_service_name << "." <<
++        (*f_iter)->get_name() << "_result>)" << " responseObserver);" << endl <<
++        indent() << "break;" << endl << endl;
++      indent_down();
++    }
+   }
++  f_service_ <<
++    indent() << "default:" << endl <<
++    indent() << "  throw new AssertionError();" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl;
++  indent_down();
++  f_service_ <<
++    indent() << "}" << endl << endl;
++
++  // invoke
++  f_service_ <<
++    indent() << "@java.lang.Override" << endl <<
++    indent() << "@java.lang.SuppressWarnings(\"unchecked\")" << endl <<
++    indent() << "public io.grpc.stub.StreamObserver<Req> invoke(" << endl <<
++    indent() << "    io.grpc.stub.StreamObserver<Resp> responseObserver) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "switch (methodId) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "default:" << endl;
++  f_service_ <<
++    indent() << "  throw new AssertionError();" << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl;
+   indent_down();
+   f_service_ << indent() << "}" << endl << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++
+ }
+ 
++void t_java_generator::generate_service_descriptors(t_service* tservice) {
++  // generate service descriptor
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  f_service_ <<
++    indent() << "public static io.grpc.ServiceDescriptor getServiceDescriptor() {" <<
++    endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return new io.grpc.ServiceDescriptor(SERVICE_NAME";
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "," << endl <<
++      indent() << "    METHOD_" << (*f_iter)->get_name();
++  }
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "," << endl <<
++        indent() << "    METHOD_" << (*f_iter)->get_name();
++    }
++  }
++  f_service_ << ");" << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++}
++
++void t_java_generator::generate_service_builder(t_service* tservice) {
++  // bind Service
++  vector<t_function*> functions = tservice->get_functions();
++  vector<t_function*>::iterator f_iter;
++  f_service_ <<
++    indent() << "@java.lang.Deprecated public static io.grpc.ServerServiceDefinition" <<
++    " bindService(" << endl <<
++    indent() << "    final " << service_name_ << " serviceImpl) {" << endl;
++  indent_up();
++  f_service_ <<
++    indent() << "return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())" <<
++    endl;
++  for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++    f_service_ <<
++      indent() << "    .addMethod(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    METHOD_" << (*f_iter)->get_name() << "," << endl <<
++      indent() << "    asyncUnaryCall(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    new MethodHandlers<" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    " << (*f_iter)->get_name() << "_args," << endl <<
++      indent() << "    " << (*f_iter)->get_name() << "_result>(" << endl;
++    indent_up();
++    f_service_ <<
++      indent() << "    serviceImpl, METHODID_" << (*f_iter)->get_name() << ")))" << endl;
++    indent_down();
++    indent_down();
++    indent_down();
++    indent_down();
++  }
++
++  if (tservice->get_extends()) {
++    t_service* extend_service = tservice->get_extends();
++    functions = extend_service->get_functions();
++    string extend_service_name = extend_service->get_name() + "Grpc";
++    for(f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
++      f_service_ <<
++        indent() << "    .addMethod(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    METHOD_" << (*f_iter)->get_name() << "," << endl <<
++        indent() << "    asyncUnaryCall(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    new MethodHandlers<" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() << "_args," << endl <<
++        indent() << "    " << extend_service_name << "." << (*f_iter)->get_name() << "_result>(" << endl;
++      indent_up();
++      f_service_ <<
++        indent() << "    serviceImpl, METHODID_" << (*f_iter)->get_name() << ")))" << endl;
++      indent_down();
++      indent_down();
++      indent_down();
++      indent_down();
++    }
++  }
++  f_service_ <<
++    indent() << "    .build();" << endl;
++  indent_down();
++  f_service_ << indent() << "}" << endl << endl;
++}
++
++
+ void t_java_generator::generate_service_async_interface(t_service* tservice) {
+   string extends = "";
+   string extends_iface = "";
+diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
+index 5865c54..1cffbe6 100755
+--- a/tutorial/Makefile.am
++++ b/tutorial/Makefile.am
+@@ -35,11 +35,6 @@ if WITH_D
+ SUBDIRS += d
+ endif
+ 
+-if WITH_JAVA
+-SUBDIRS += java
+-SUBDIRS += js
+-endif
+-
+ if WITH_PYTHON
+ SUBDIRS += py
+ SUBDIRS += py.twisted
+@@ -95,4 +90,5 @@ EXTRA_DIST = \
+ 	php \
+ 	shared.thrift \
+ 	tutorial.thrift \
+-	README.md
++	README.md \
++	java
+-- 
+2.8.0.rc3.226.g39d4020
+
diff --git a/tools/profiling/latency_profile/profile_analyzer.py b/tools/profiling/latency_profile/profile_analyzer.py
index dad0712..48b8e9b 100755
--- a/tools/profiling/latency_profile/profile_analyzer.py
+++ b/tools/profiling/latency_profile/profile_analyzer.py
@@ -43,6 +43,7 @@
 TIME_TO_SCOPE_END = object()
 TIME_FROM_STACK_START = object()
 TIME_TO_STACK_END = object()
+TIME_FROM_LAST_IMPORTANT = object()
 
 
 argp = argparse.ArgumentParser(description='Process output of basic_prof builds')
@@ -78,10 +79,14 @@
     self.call_stack_builder.lines.append(line_item)
 
   def finish(self, line):
-    assert line['tag'] == self.top_line.tag, 'expected %s, got %s; thread=%s; t0=%f t1=%f' % (self.top_line.tag, line['tag'], line['thd'], self.top_line.start_time, line['t'])
+    assert line['tag'] == self.top_line.tag, (
+        'expected %s, got %s; thread=%s; t0=%f t1=%f' %
+        (self.top_line.tag, line['tag'], line['thd'], self.top_line.start_time,
+         line['t']))
     final_time_stamp = line['t']
     assert self.top_line.end_time is None
     self.top_line.end_time = final_time_stamp
+    self.top_line.important = self.top_line.important or line['imp']
     assert SELF_TIME not in self.top_line.times
     self.top_line.times[SELF_TIME] = final_time_stamp - self.top_line.start_time
     for line in self.call_stack_builder.lines[self.first_child_pos:]:
@@ -101,9 +106,14 @@
     start_time = self.lines[0].start_time
     end_time = self.lines[0].end_time
     self.signature = self.signature.hexdigest()
+    last_important = start_time
     for line in self.lines:
       line.times[TIME_FROM_STACK_START] = line.start_time - start_time
       line.times[TIME_TO_STACK_END] = end_time - line.end_time
+      line.times[TIME_FROM_LAST_IMPORTANT] = line.start_time - last_important
+      if line.important:
+        last_important = line.end_time
+    last_important = end_time
 
   def add(self, line):
     line_type = line['type']
@@ -113,7 +123,9 @@
       self.stk.append(ScopeBuilder(self, line))
       return False
     elif line_type == '}':
-      assert self.stk, 'expected non-empty stack for closing %s; thread=%s; t=%f' % (line['tag'], line['thd'], line['t'])
+      assert self.stk, (
+          'expected non-empty stack for closing %s; thread=%s; t=%f' %
+          (line['tag'], line['thd'], line['t']))
       self.stk.pop().finish(line)
       if not self.stk:
         self.finish()
@@ -216,9 +228,16 @@
     return ''
   return ent
 
+BANNER = {
+    'simple': 'Count: %(count)d',
+    'html': '<h1>Count: %(count)d</h1>'
+}
+
 FORMAT = [
   ('TAG', lambda line: '..'*line.indent + tidy_tag(line.tag)),
   ('LOC', lambda line: '%s:%d' % (line.filename[line.filename.rfind('/')+1:], line.fileline)),
+  ('IMP', lambda line: '*' if line.important else ''),
+  ('FROM_IMP', time_format(TIME_FROM_LAST_IMPORTANT)),
   ('FROM_STACK_START', time_format(TIME_FROM_STACK_START)),
   ('SELF', time_format(SELF_TIME)),
   ('TO_STACK_END', time_format(TIME_TO_STACK_END)),
@@ -227,11 +246,6 @@
   ('TO_SCOPE_END', time_format(TIME_TO_SCOPE_END)),
 ]
 
-BANNER = {
-    'simple': 'Count: %(count)d',
-    'html': '<h1>Count: %(count)d</h1>'
-}
-
 if args.fmt == 'html':
   print '<html>'
   print '<head>'
diff --git a/tools/run_tests/artifact_targets.py b/tools/run_tests/artifact_targets.py
index 0ba9f3b..d36f963 100644
--- a/tools/run_tests/artifact_targets.py
+++ b/tools/run_tests/artifact_targets.py
@@ -45,7 +45,7 @@
   environ['RUN_COMMAND'] = shell_command
 
   docker_args=[]
-  for k,v in environ.iteritems():
+  for k,v in environ.items():
     docker_args += ['-e', '%s=%s' % (k, v)]
   docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
                 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh',
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index d2ff1c6..b786c47 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -128,19 +128,6 @@
     fi
   fi
 fi
-# TODO(atash) consider conceptualizing MinGW as a first-class platform and move
-# these flags into our `setup.py`s
-if [ $(is_mingw) ]; then
-  # We're on MinGW, and our CFLAGS and LDFLAGS will be eaten by the void. Use
-  # our work-around environment variables instead.
-  PYTHON_MSVCR=`$PYTHON -c "from distutils.cygwinccompiler import get_msvcr; print(get_msvcr()[0])"`
-  export GRPC_PYTHON_LDFLAGS="-static-libgcc -static-libstdc++ -mcrtdll=$PYTHON_MSVCR -static -lpthread"
-  # See https://sourceforge.net/p/mingw-w64/bugs/363/
-  export GRPC_PYTHON_CFLAGS="-D_ftime=_ftime64 -D_timeb=__timeb64"
-  # TODO(atash) set these flags for only grpcio-tools (they don't do any harm to
-  # grpcio, but they result in noisy warnings).
-  export GRPC_PYTHON_CFLAGS="-frtti -std=c++11 $GRPC_PYTHON_CFLAGS"
-fi
 
 ############################
 # Perform build operations #
diff --git a/tools/run_tests/distribtest_targets.py b/tools/run_tests/distribtest_targets.py
index 1a7aa0b..7930f2a 100644
--- a/tools/run_tests/distribtest_targets.py
+++ b/tools/run_tests/distribtest_targets.py
@@ -41,7 +41,7 @@
   environ['RELATIVE_COPY_PATH'] = 'test/distrib'
 
   docker_args=[]
-  for k,v in environ.iteritems():
+  for k,v in environ.items():
     docker_args += ['-e', '%s=%s' % (k, v)]
   docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
                 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh'}
diff --git a/tools/run_tests/dockerjob.py b/tools/run_tests/dockerjob.py
index e4ca3b7..4a7e61b 100755
--- a/tools/run_tests/dockerjob.py
+++ b/tools/run_tests/dockerjob.py
@@ -29,6 +29,8 @@
 
 """Helpers to run docker instances as jobs."""
 
+from __future__ import print_function
+
 import jobset
 import tempfile
 import time
@@ -95,7 +97,7 @@
                        stderr=subprocess.STDOUT) == 0:
       return True
     time.sleep(2)
-  print 'Failed to remove docker image %s' % image
+  print('Failed to remove docker image %s' % image)
   return False
 
 
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index 3999537..b6fb631 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -29,6 +29,8 @@
 
 """Run a group of subprocesses and then finish."""
 
+from __future__ import print_function
+
 import multiprocessing
 import os
 import platform
@@ -123,8 +125,8 @@
   try:
     if platform_string() == 'windows' or not sys.stdout.isatty():
       if explanatory_text:
-        print explanatory_text
-      print '%s: %s' % (tag, msg)
+        print(explanatory_text)
+      print('%s: %s' % (tag, msg))
       return
     sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % (
         _BEGINNING_OF_LINE,
@@ -368,7 +370,7 @@
               self._travis,
               self._add_env)
     self._running.add(job)
-    if not self.resultset.has_key(job.GetSpec().shortname):
+    if job.GetSpec().shortname not in self.resultset:
       self.resultset[job.GetSpec().shortname] = []
     return True
 
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/package_targets.py
index 8217d76..5e6de2e 100644
--- a/tools/run_tests/package_targets.py
+++ b/tools/run_tests/package_targets.py
@@ -39,7 +39,7 @@
   environ['RUN_COMMAND'] = shell_command
 
   docker_args=[]
-  for k,v in environ.iteritems():
+  for k,v in environ.items():
     docker_args += ['-e', '%s=%s' % (k, v)]
   docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
                 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh',
diff --git a/tools/run_tests/port_server.py b/tools/run_tests/port_server.py
index 83f8e6c..e9b3f7f 100755
--- a/tools/run_tests/port_server.py
+++ b/tools/run_tests/port_server.py
@@ -30,8 +30,10 @@
 
 """Manage TCP ports for unit tests; started by run_tests.py"""
 
+from __future__ import print_function
+
 import argparse
-import BaseHTTPServer
+from six.moves import BaseHTTPServer
 import hashlib
 import os
 import socket
@@ -46,7 +48,7 @@
 
 
 if len(sys.argv) == 2 and sys.argv[1] == 'dump_version':
-  print _MY_VERSION
+  print(_MY_VERSION)
   sys.exit(0)
 
 
@@ -62,7 +64,7 @@
   sys.stderr = open(args.logfile, 'w')
   sys.stdout = sys.stderr
 
-print 'port server running on port %d' % args.port
+print('port server running on port %d' % args.port)
 
 pool = []
 in_use = {}
@@ -152,7 +154,7 @@
       self.send_header('Content-Type', 'text/plain')
       self.end_headers()
       now = time.time()
-      self.wfile.write(yaml.dump({'pool': pool, 'in_use': dict((k, now - v) for k, v in in_use.iteritems())}))
+      self.wfile.write(yaml.dump({'pool': pool, 'in_use': dict((k, now - v) for k, v in in_use.items())}))
     elif self.path == '/quitquitquit':
       self.send_response(200)
       self.end_headers()
@@ -164,4 +166,4 @@
   httpd.handle_request()
   sys.stderr.flush()
 
-print 'done'
+print('done')
diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/report_utils.py
index 35dcaca..5648a69 100644
--- a/tools/run_tests/report_utils.py
+++ b/tools/run_tests/report_utils.py
@@ -29,6 +29,8 @@
 
 """Generate XML and HTML test reports."""
 
+from __future__ import print_function
+
 try:
   from mako.runtime import Context
   from mako.template import Template
@@ -60,7 +62,7 @@
   root = ET.Element('testsuites')
   testsuite = ET.SubElement(root, 'testsuite', id='1', package='grpc', 
                             name='tests')
-  for shortname, results in resultset.iteritems(): 
+  for shortname, results in resultset.items():
     for result in results:
       xml_test = ET.SubElement(testsuite, 'testcase', name=shortname) 
       if result.elapsed_time:
@@ -83,10 +85,10 @@
   try:
     mytemplate = Template(filename=template_file, format_exceptions=True)
   except NameError:
-    print 'Mako template is not installed. Skipping HTML report generation.'
+    print('Mako template is not installed. Skipping HTML report generation.')
     return
   except IOError as e:
-    print 'Failed to find the template %s: %s' % (template_file, e)
+    print('Failed to find the template %s: %s' % (template_file, e))
     return
 
   sorted_test_cases = sorted(test_cases)
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 782e316..0d402d6 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -30,6 +30,8 @@
 
 """Run interop (cross-language) tests in parallel."""
 
+from __future__ import print_function
+
 import argparse
 import atexit
 import dockerjob
@@ -311,7 +313,7 @@
     return {}
 
   def unimplemented_test_cases(self):
-    return _SKIP_ADVANCED + _SKIP_COMPRESSION
+    return _SKIP_ADVANCED + _SKIP_SERVER_COMPRESSION
 
   def unimplemented_test_cases_server(self):
     return _SKIP_ADVANCED + _SKIP_COMPRESSION
@@ -398,7 +400,7 @@
 
   # turn environ into -e docker args
   if environ:
-    for k,v in environ.iteritems():
+    for k,v in environ.items():
       docker_cmdline += ['-e', '%s=%s' % (k,v)]
 
   # set working directory
@@ -660,7 +662,7 @@
                         'cloud_to_prod_auth tests against.'))
 argp.add_argument('-s', '--server',
                   choices=['all'] + sorted(_SERVERS),
-                  action='append',
+                  nargs='+',
                   help='Run cloud_to_cloud servers in a separate docker ' +
                        'image. Servers can only be started automatically if ' +
                        '--use_docker option is enabled.',
@@ -700,15 +702,15 @@
 
 if args.use_docker:
   if not args.travis:
-    print 'Seen --use_docker flag, will run interop tests under docker.'
-    print
-    print 'IMPORTANT: The changes you are testing need to be locally committed'
-    print 'because only the committed changes in the current branch will be'
-    print 'copied to the docker environment.'
+    print('Seen --use_docker flag, will run interop tests under docker.')
+    print('')
+    print('IMPORTANT: The changes you are testing need to be locally committed')
+    print('because only the committed changes in the current branch will be')
+    print('copied to the docker environment.')
     time.sleep(5)
 
 if not args.use_docker and servers:
-  print 'Running interop servers is only supported with --use_docker option enabled.'
+  print('Running interop servers is only supported with --use_docker option enabled.')
   sys.exit(1)
 
 languages = set(_LANGUAGES[l]
@@ -794,7 +796,7 @@
     (server_host, server_port) = server[1].split(':')
     server_addresses[server_name] = (server_host, server_port)
 
-  for server_name, server_address in server_addresses.iteritems():
+  for server_name, server_address in server_addresses.items():
     (server_host, server_port) = server_address
     server_language = _LANGUAGES.get(server_name, None)
     skip_server = []  # test cases unimplemented by server
@@ -826,7 +828,7 @@
         jobs.append(test_job)
 
   if not jobs:
-    print 'No jobs to run.'
+    print('No jobs to run.')
     for image in docker_images.itervalues():
       dockerjob.remove_image(image, skip_nonexistent=True)
     sys.exit(1)
@@ -840,7 +842,7 @@
 
   report_utils.render_junit_xml_report(resultset, 'report.xml')
 
-  for name, job in resultset.iteritems():
+  for name, job in resultset.items():
     if "http2" in name:
       job[0].http2results = aggregate_http2_results(job[0].message)
 
@@ -852,12 +854,12 @@
 
 finally:
   # Check if servers are still running.
-  for server, job in server_jobs.iteritems():
+  for server, job in server_jobs.items():
     if not job.is_running():
-      print 'Server "%s" has exited prematurely.' % server
+      print('Server "%s" has exited prematurely.' % server)
 
   dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
 
   for image in docker_images.itervalues():
-    print 'Removing docker image %s' % image
+    print('Removing docker image %s' % image)
     dockerjob.remove_image(image)
diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py
index 14901ca..5fdf7a4 100755
--- a/tools/run_tests/run_performance_tests.py
+++ b/tools/run_tests/run_performance_tests.py
@@ -30,6 +30,8 @@
 
 """Run performance tests locally or remotely."""
 
+from __future__ import print_function
+
 import argparse
 import itertools
 import jobset
@@ -310,7 +312,7 @@
                             'in the same scenario')
           if custom_server_lang:
             if not workers_by_lang.get(custom_server_lang, []):
-              print 'Warning: Skipping scenario %s as' % scenario_json['name']
+              print('Warning: Skipping scenario %s as' % scenario_json['name'])
               print('SERVER_LANGUAGE is set to %s yet the language has '
                     'not been selected with -l' % custom_server_lang)
               continue
@@ -319,7 +321,7 @@
               workers[idx] = workers_by_lang[custom_server_lang][idx]
           if custom_client_lang:
             if not workers_by_lang.get(custom_client_lang, []):
-              print 'Warning: Skipping scenario %s as' % scenario_json['name']
+              print('Warning: Skipping scenario %s as' % scenario_json['name'])
               print('CLIENT_LANGUAGE is set to %s yet the language has '
                     'not been selected with -l' % custom_client_lang)
               continue
@@ -344,14 +346,14 @@
   while any(job.is_running() for job in jobs):
     for job in qpsworker_jobs:
       if job.is_running():
-        print 'QPS worker "%s" is still running.' % job.host_and_port
+        print('QPS worker "%s" is still running.' % job.host_and_port)
     if retries > 10:
-      print 'Killing all QPS workers.'
+      print('Killing all QPS workers.')
       for job in jobs:
         job.kill()
     retries += 1
     time.sleep(3)
-  print 'All QPS workers finished.'
+  print('All QPS workers finished.')
 
 
 argp = argparse.ArgumentParser(description='Run performance tests.')
diff --git a/tools/run_tests/run_stress_tests.py b/tools/run_tests/run_stress_tests.py
index e42ee24..de4a228 100755
--- a/tools/run_tests/run_stress_tests.py
+++ b/tools/run_tests/run_stress_tests.py
@@ -29,6 +29,8 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 """Run stress test in C++"""
 
+from __future__ import print_function
+
 import argparse
 import atexit
 import dockerjob
@@ -93,7 +95,7 @@
 
   # turn environ into -e docker args
   if environ:
-    for k, v in environ.iteritems():
+    for k, v in environ.items():
       docker_cmdline += ['-e', '%s=%s' % (k, v)]
 
   # set working directory
@@ -140,7 +142,7 @@
       '--num_channels_per_server=%s' % num_channels_per_server,
       '--metrics_port=%s' % metrics_port
   ]))
-  print cmdline
+  print(cmdline)
   cwd = language.client_cwd
   environ = language.global_env()
   if docker_image:
@@ -287,7 +289,7 @@
     (server_host, server_port) = server[1].split(':')
     server_addresses[server_name] = (server_host, server_port)
 
-  for server_name, server_address in server_addresses.iteritems():
+  for server_name, server_address in server_addresses.items():
     (server_host, server_port) = server_address
     for language in languages:
       test_job = cloud_to_cloud_jobspec(
@@ -302,7 +304,7 @@
       jobs.append(test_job)
 
   if not jobs:
-    print 'No jobs to run.'
+    print('No jobs to run.')
     for image in docker_images.itervalues():
       dockerjob.remove_image(image, skip_nonexistent=True)
     sys.exit(1)
@@ -317,12 +319,12 @@
 
 finally:
   # Check if servers are still running.
-  for server, job in server_jobs.iteritems():
+  for server, job in server_jobs.items():
     if not job.is_running():
-      print 'Server "%s" has exited prematurely.' % server
+      print('Server "%s" has exited prematurely.' % server)
 
   dockerjob.finish_jobs([j for j in server_jobs.itervalues()])
 
   for image in docker_images.itervalues():
-    print 'Removing docker image %s' % image
+    print('Removing docker image %s' % image)
     dockerjob.remove_image(image)
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 8dcffd7..78ef05b 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -30,6 +30,8 @@
 
 """Run tests in parallel."""
 
+from __future__ import print_function
+
 import argparse
 import ast
 import collections
@@ -49,7 +51,7 @@
 import tempfile
 import traceback
 import time
-import urllib2
+from six.moves import urllib
 import uuid
 
 import jobset
@@ -99,7 +101,7 @@
                        would like to run
     """
     actual_environ = self.environ.copy()
-    for k, v in environ.iteritems():
+    for k, v in environ.items():
       actual_environ[k] = v
     return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
                           shortname=shortname,
@@ -137,6 +139,53 @@
   return True if os.getenv('RUN_TESTS_COMMAND') else False
 
 
+_PythonConfigVars = collections.namedtuple(
+  '_ConfigVars', ['shell', 'builder', 'builder_prefix_arguments',
+                  'venv_relative_python', 'toolchain', 'runner'])
+
+
+def _python_config_generator(name, major, minor, bits, config_vars):
+  return PythonConfig(
+    name,
+    config_vars.shell + config_vars.builder + config_vars.builder_prefix_arguments + [
+      _python_pattern_function(major=major, minor=minor, bits=bits)] + [
+      name] + config_vars.venv_relative_python + config_vars.toolchain,
+    config_vars.shell + config_vars.runner + [
+      os.path.join(name, config_vars.venv_relative_python[0])])
+
+
+def _pypy_config_generator(name, major, config_vars):
+  return PythonConfig(
+    name,
+    config_vars.shell + config_vars.builder + config_vars.builder_prefix_arguments + [
+      _pypy_pattern_function(major=major)] + [
+      name] + config_vars.venv_relative_python + config_vars.toolchain,
+    config_vars.shell + config_vars.runner + [
+      os.path.join(name, config_vars.venv_relative_python[0])])
+
+
+def _python_pattern_function(major, minor, bits):
+  # Bit-ness is handled by the test machine's environment
+  if os.name == "nt":
+    if bits == "64":
+      return '/c/Python{major}{minor}/python.exe'.format(
+        major=major, minor=minor, bits=bits)
+    else:
+      return '/c/Python{major}{minor}_{bits}bits/python.exe'.format(
+        major=major, minor=minor, bits=bits)
+  else:
+    return 'python{major}.{minor}'.format(major=major, minor=minor)
+
+
+def _pypy_pattern_function(major):
+  if major == '2':
+    return 'pypy'
+  elif major == '3':
+    return 'pypy3'
+  else:
+    raise ValueError("Unknown PyPy major version")
+
+
 class CLanguage(object):
 
   def __init__(self, make_target, test_lang):
@@ -213,7 +262,7 @@
                                             timeout_seconds=target.get('timeout_seconds', _DEFAULT_TIMEOUT_SECONDS),
                                             environ=env))
         elif self.args.regex == '.*' or self.platform == 'windows':
-          print '\nWARNING: binary not found, skipping', binary
+          print('\nWARNING: binary not found, skipping', binary)
     return sorted(out)
 
   def make_targets(self):
@@ -434,7 +483,7 @@
     return [self.config.job_spec(
         config.run,
         timeout_seconds=5*60,
-        environ=dict(environment.items() +
+        environ=dict(list(environment.items()) +
                      [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
         shortname='%s.test.%s' % (config.name, suite_name),)
         for suite_name in tests_json
@@ -459,41 +508,50 @@
     return 'Makefile'
 
   def dockerfile_dir(self):
-    return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(self.args.arch)
+    return 'tools/dockerfile/test/python_%s_%s' % (self.python_manager_name(), _docker_arch_suffix(self.args.arch))
+
+  def python_manager_name(self):
+    return 'pyenv' if self.args.compiler in ['python3.5', 'python3.6'] else 'jessie'
 
   def _get_pythons(self, args):
     if args.arch == 'x86':
       bits = '32'
     else:
       bits = '64'
+
     if os.name == 'nt':
       shell = ['bash']
       builder = [os.path.abspath('tools/run_tests/build_python_msys2.sh')]
       builder_prefix_arguments = ['MINGW{}'.format(bits)]
       venv_relative_python = ['Scripts/python.exe']
       toolchain = ['mingw32']
-      python_pattern_function = lambda major, minor, bits: (
-          '/c/Python{major}{minor}/python.exe'.format(major=major, minor=minor, bits=bits)
-	  if bits == '64' else
-	  '/c/Python{major}{minor}_{bits}bits/python.exe'.format(
-              major=major, minor=minor, bits=bits))
     else:
       shell = []
       builder = [os.path.abspath('tools/run_tests/build_python.sh')]
       builder_prefix_arguments = []
       venv_relative_python = ['bin/python']
       toolchain = ['unix']
-      # Bit-ness is handled by the test machine's environment
-      python_pattern_function = lambda major, minor, bits: 'python{major}.{minor}'.format(major=major, minor=minor)
+
     runner = [os.path.abspath('tools/run_tests/run_python.sh')]
-    python_config_generator = lambda name, major, minor, bits: PythonConfig(
-        name,
-        shell + builder + builder_prefix_arguments
-	    + [python_pattern_function(major=major, minor=minor, bits=bits)]
-	    + [name] + venv_relative_python + toolchain,
-        shell + runner + [os.path.join(name, venv_relative_python[0])])
-    python27_config = python_config_generator(name='py27', major='2', minor='7', bits=bits)
-    python34_config = python_config_generator(name='py34', major='3', minor='4', bits=bits)
+    config_vars = _PythonConfigVars(shell, builder, builder_prefix_arguments,
+                              venv_relative_python, toolchain, runner)
+    python27_config = _python_config_generator(name='py27', major='2',
+                                               minor='7', bits=bits,
+                                               config_vars=config_vars)
+    python34_config = _python_config_generator(name='py34', major='3',
+                                               minor='4', bits=bits,
+                                               config_vars=config_vars)
+    python35_config = _python_config_generator(name='py35', major='3',
+                                               minor='5', bits=bits,
+                                               config_vars=config_vars)
+    python36_config = _python_config_generator(name='py36', major='3',
+                                               minor='6', bits=bits,
+                                               config_vars=config_vars)
+    pypy27_config = _pypy_config_generator(name='pypy', major='2',
+                                           config_vars=config_vars)
+    pypy32_config = _pypy_config_generator(name='pypy3', major='3',
+                                           config_vars=config_vars)
+
     if args.compiler == 'default':
       if os.name == 'nt':
         return (python27_config,)
@@ -503,6 +561,14 @@
       return (python27_config,)
     elif args.compiler == 'python3.4':
       return (python34_config,)
+    elif args.compiler == 'python3.5':
+      return (python35_config,)
+    elif args.compiler == 'python3.6':
+      return (python36_config,)
+    elif args.compiler == 'pypy':
+      return (pypy27_config,)
+    elif args.compiler == 'pypy3':
+      return (pypy32_config,)
     else:
       raise Exception('Compiler %s not supported.' % args.compiler)
 
@@ -696,7 +762,7 @@
                               shortname='objc-tests',
                               environ=_FORCE_ENVIRON_FOR_WRAPPERS),
         self.config.job_spec(['src/objective-c/tests/build_example_test.sh'],
-                              timeout_seconds=15*60,
+                              timeout_seconds=30*60,
                               shortname='objc-examples-build',
                               environ=_FORCE_ENVIRON_FOR_WRAPPERS),
     ]
@@ -799,7 +865,7 @@
   elif arch == 'x64':
     return '/p:Platform=x64'
   else:
-    print 'Architecture %s not supported.' % arch
+    print('Architecture %s not supported.' % arch)
     sys.exit(1)
 
 
@@ -817,11 +883,11 @@
     elif runtime_arch == '32bit' and arch == 'x86':
       return
     else:
-      print 'Architecture %s does not match current runtime architecture.' % arch
+      print('Architecture %s does not match current runtime architecture.' % arch)
       sys.exit(1)
   else:
     if args.arch != 'default':
-      print 'Architecture %s not supported on current platform.' % args.arch
+      print('Architecture %s not supported on current platform.' % args.arch)
       sys.exit(1)
 
 
@@ -835,7 +901,7 @@
   elif compiler == 'vs2010':
     return 'vsprojects\\build_vs2010.bat'
   else:
-    print 'Compiler %s not supported.' % compiler
+    print('Compiler %s not supported.' % compiler)
     sys.exit(1)
 
 
@@ -849,7 +915,7 @@
   elif compiler == 'vs2010':
     return '/p:PlatformToolset=v100'
   else:
-    print 'Compiler %s not supported.' % compiler
+    print('Compiler %s not supported.' % compiler)
     sys.exit(1)
 
 
@@ -860,7 +926,7 @@
   elif arch == 'x86':
     return 'x86'
   else:
-    print 'Architecture %s not supported with current settings.' % arch
+    print('Architecture %s not supported with current settings.' % arch)
     sys.exit(1)
 
 
@@ -884,6 +950,7 @@
         msg = '\'{}\' is not a positive integer or \'inf\''.format(arg_str)
         raise argparse.ArgumentTypeError(msg)
 
+
 # parse command line
 argp = argparse.ArgumentParser(description='Run grpc tests.')
 argp.add_argument('-c', '--config',
@@ -937,7 +1004,7 @@
                            'gcc4.4', 'gcc4.6', 'gcc4.9', 'gcc5.3',
                            'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
                            'vs2010', 'vs2013', 'vs2015',
-                           'python2.7', 'python3.4',
+                           'python2.7', 'python3.4', 'python3.5', 'python3.6', 'pypy', 'pypy3',
                            'node0.12', 'node4', 'node5',
                            'coreclr'],
                   default='default',
@@ -976,7 +1043,7 @@
     branch = spec[1]
   cwd = 'third_party/%s' % submodule
   def git(cmd, cwd=cwd):
-    print 'in %s: git %s' % (cwd, cmd)
+    print('in %s: git %s' % (cwd, cmd))
     subprocess.check_call('git %s' % cmd, cwd=cwd, shell=True)
   git('fetch')
   git('checkout %s' % branch)
@@ -987,8 +1054,8 @@
   if jobset.platform_string() == 'linux':
     subprocess.check_call('tools/buildgen/generate_projects.sh', shell=True)
   else:
-    print 'WARNING: may need to regenerate projects, but since we are not on'
-    print '         Linux this step is being skipped. Compilation MAY fail.'
+    print('WARNING: may need to regenerate projects, but since we are not on')
+    print('         Linux this step is being skipped. Compilation MAY fail.')
 
 
 # grab config
@@ -1015,18 +1082,18 @@
 language_make_options=[]
 if any(language.make_options() for language in languages):
   if not 'gcov' in args.config and len(languages) != 1:
-    print 'languages with custom make options cannot be built simultaneously with other languages'
+    print('languages with custom make options cannot be built simultaneously with other languages')
     sys.exit(1)
   else:
     language_make_options = next(iter(languages)).make_options()
 
 if args.use_docker:
   if not args.travis:
-    print 'Seen --use_docker flag, will run tests under docker.'
-    print
-    print 'IMPORTANT: The changes you are testing need to be locally committed'
-    print 'because only the committed changes in the current branch will be'
-    print 'copied to the docker environment.'
+    print('Seen --use_docker flag, will run tests under docker.')
+    print('')
+    print('IMPORTANT: The changes you are testing need to be locally committed')
+    print('because only the committed changes in the current branch will be')
+    print('copied to the docker environment.')
     time.sleep(5)
 
   dockerfile_dirs = set([l.dockerfile_dir() for l in languages])
@@ -1110,7 +1177,7 @@
                    for l in languages
                    for cmdline in l.pre_build_steps()))
 if make_targets:
-  make_commands = itertools.chain.from_iterable(make_jobspec(build_config, list(targets), makefile) for (makefile, targets) in make_targets.iteritems())
+  make_commands = itertools.chain.from_iterable(make_jobspec(build_config, list(targets), makefile) for (makefile, targets) in make_targets.items())
   build_steps.extend(set(make_commands))
 build_steps.extend(set(
                    jobset.JobSpec(cmdline, environ=build_step_environ(build_config), timeout_seconds=None)
@@ -1127,13 +1194,13 @@
 
 def _shut_down_legacy_server(legacy_server_port):
   try:
-    version = int(urllib2.urlopen(
+    version = int(urllib.request.urlopen(
         'http://localhost:%d/version_number' % legacy_server_port,
         timeout=10).read())
   except:
     pass
   else:
-    urllib2.urlopen(
+    urllib.request.urlopen(
         'http://localhost:%d/quitquitquit' % legacy_server_port).read()
 
 
@@ -1155,29 +1222,29 @@
   # if not running ==> start a new one
   # otherwise, leave it up
   try:
-    version = int(urllib2.urlopen(
+    version = int(urllib.request.urlopen(
         'http://localhost:%d/version_number' % port_server_port,
         timeout=10).read())
-    print 'detected port server running version %d' % version
+    print('detected port server running version %d' % version)
     running = True
   except Exception as e:
-    print 'failed to detect port server: %s' % sys.exc_info()[0]
-    print e.strerror
+    print('failed to detect port server: %s' % sys.exc_info()[0])
+    print(e.strerror)
     running = False
   if running:
     current_version = int(subprocess.check_output(
         [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
          'dump_version']))
-    print 'my port server is version %d' % current_version
+    print('my port server is version %d' % current_version)
     running = (version >= current_version)
     if not running:
-      print 'port_server version mismatch: killing the old one'
-      urllib2.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
+      print('port_server version mismatch: killing the old one')
+      urllib.request.urlopen('http://localhost:%d/quitquitquit' % port_server_port).read()
       time.sleep(1)
   if not running:
     fd, logfile = tempfile.mkstemp()
     os.close(fd)
-    print 'starting port_server, with log file %s' % logfile
+    print('starting port_server, with log file %s' % logfile)
     args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
             '-p', '%d' % port_server_port, '-l', logfile]
     env = dict(os.environ)
@@ -1203,34 +1270,34 @@
     waits = 0
     while True:
       if waits > 10:
-        print 'killing port server due to excessive start up waits'
+        print('killing port server due to excessive start up waits')
         port_server.kill()
       if port_server.poll() is not None:
-        print 'port_server failed to start'
+        print('port_server failed to start')
         # try one final time: maybe another build managed to start one
         time.sleep(1)
         try:
-          urllib2.urlopen('http://localhost:%d/get' % port_server_port,
+          urllib.request.urlopen('http://localhost:%d/get' % port_server_port,
                           timeout=1).read()
-          print 'last ditch attempt to contact port server succeeded'
+          print('last ditch attempt to contact port server succeeded')
           break
         except:
           traceback.print_exc()
           port_log = open(logfile, 'r').read()
-          print port_log
+          print(port_log)
           sys.exit(1)
       try:
-        urllib2.urlopen('http://localhost:%d/get' % port_server_port,
+        urllib.request.urlopen('http://localhost:%d/get' % port_server_port,
                         timeout=1).read()
-        print 'port server is up and ready'
+        print('port server is up and ready')
         break
       except socket.timeout:
-        print 'waiting for port_server: timeout'
+        print('waiting for port_server: timeout')
         traceback.print_exc();
         time.sleep(1)
         waits += 1
-      except urllib2.URLError:
-        print 'waiting for port_server: urlerror'
+      except urllib.error.URLError:
+        print('waiting for port_server: urlerror')
         traceback.print_exc();
         time.sleep(1)
         waits += 1
diff --git a/tools/run_tests/sanity/check_sources_and_headers.py b/tools/run_tests/sanity/check_sources_and_headers.py
index c028499..28c1dc4 100755
--- a/tools/run_tests/sanity/check_sources_and_headers.py
+++ b/tools/run_tests/sanity/check_sources_and_headers.py
@@ -55,7 +55,8 @@
   for dep in target['deps']:
     if target_has_header(get_target(dep), name):
       return True
-  if name == 'src/core/lib/profiling/stap_probes.h':
+  if name in ['src/core/lib/profiling/stap_probes.h',
+              'src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h']:
     return True
   return False
 
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 04123ee..d2ab5b0 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -47,6 +47,7 @@
  f8ac463766281625ad710900479130c7fcb4d63b third_party/nanopb (nanopb-0.3.4-29-gf8ac463)
  e8ae137c96444ea313485ed1118c5e43b2099cf1 third_party/protobuf (v3.0.0-beta-4-74-ge8ae137)
  50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
+ bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift
 EOF
 
 diff -u $submodules $want_submodules
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index cd1757a..11daf24 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -149,6 +149,22 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "census_resource_test", 
+    "src": [
+      "test/core/census/resource_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "channel_create_test", 
     "src": [
       "test/core/surface/channel_create_test.c"
@@ -1685,7 +1701,7 @@
     "language": "c", 
     "name": "timeout_encoding_test", 
     "src": [
-      "test/core/transport/chttp2/timeout_encoding_test.c"
+      "test/core/transport/timeout_encoding_test.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -2102,6 +2118,24 @@
     ], 
     "headers": [], 
     "language": "c++", 
+    "name": "filter_end2end_test", 
+    "src": [
+      "test/cpp/end2end/filter_end2end_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
     "name": "generic_end2end_test", 
     "src": [
       "test/cpp/end2end/generic_end2end_test.cc"
@@ -2130,13 +2164,11 @@
   {
     "deps": [
       "gpr", 
-      "gpr_test_util", 
       "grpc", 
       "grpc++", 
+      "grpc++_reflection", 
       "grpc++_test_config", 
-      "grpc++_test_util", 
-      "grpc_cli_libs", 
-      "grpc_test_util"
+      "grpc_cli_libs"
     ], 
     "headers": [], 
     "language": "c++", 
@@ -2227,6 +2259,35 @@
   }, 
   {
     "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_codegen_proto", 
+      "grpc++_config_proto", 
+      "grpc++_reflection", 
+      "grpc_cli_libs", 
+      "grpc_test_util"
+    ], 
+    "headers": [
+      "src/proto/grpc/testing/echo.grpc.pb.h", 
+      "src/proto/grpc/testing/echo.pb.h", 
+      "src/proto/grpc/testing/echo_messages.grpc.pb.h", 
+      "src/proto/grpc/testing/echo_messages.pb.h", 
+      "test/cpp/util/string_ref_helper.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc_tool_test", 
+    "src": [
+      "test/cpp/util/grpc_tool_test.cc", 
+      "test/cpp/util/string_ref_helper.cc", 
+      "test/cpp/util/string_ref_helper.h"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "grpc", 
       "grpc++", 
       "grpc++_test_util", 
@@ -2253,6 +2314,27 @@
       "grpc++_test_util", 
       "grpc_test_util"
     ], 
+    "headers": [
+      "src/proto/grpc/lb/v1/load_balancer.grpc.pb.h", 
+      "src/proto/grpc/lb/v1/load_balancer.pb.h"
+    ], 
+    "language": "c++", 
+    "name": "grpclb_test", 
+    "src": [
+      "test/cpp/grpclb/grpclb_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
     "headers": [], 
     "language": "c++", 
     "name": "hybrid_end2end_test", 
@@ -2291,6 +2373,7 @@
       "grpc++_test_util", 
       "grpc_test_util", 
       "interop_server_helper", 
+      "interop_server_lib", 
       "interop_server_main"
     ], 
     "headers": [], 
@@ -3609,9 +3692,9 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "src": [
-      "test/core/end2end/fixtures/h2_loadreporting.c"
+      "test/core/end2end/fixtures/h2_load_reporting.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -3881,9 +3964,9 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "src": [
-      "test/core/end2end/fixtures/h2_loadreporting.c"
+      "test/core/end2end/fixtures/h2_load_reporting.c"
     ], 
     "third_party": false, 
     "type": "target"
@@ -4229,6 +4312,7 @@
       "gpr", 
       "gpr_test_util", 
       "grpc", 
+      "grpc_base", 
       "grpc_test_util_base"
     ], 
     "headers": [
@@ -4361,25 +4445,19 @@
   {
     "deps": [
       "grpc++", 
-      "grpc++_codegen_proto"
+      "grpc++_reflection_proto"
     ], 
     "headers": [
       "include/grpc++/ext/proto_server_reflection_plugin.h", 
-      "include/grpc++/ext/reflection.grpc.pb.h", 
-      "include/grpc++/ext/reflection.pb.h", 
       "src/cpp/ext/proto_server_reflection.h"
     ], 
     "language": "c++", 
     "name": "grpc++_reflection", 
     "src": [
       "include/grpc++/ext/proto_server_reflection_plugin.h", 
-      "include/grpc++/ext/reflection.grpc.pb.h", 
-      "include/grpc++/ext/reflection.pb.h", 
       "src/cpp/ext/proto_server_reflection.cc", 
       "src/cpp/ext/proto_server_reflection.h", 
-      "src/cpp/ext/proto_server_reflection_plugin.cc", 
-      "src/cpp/ext/reflection.grpc.pb.cc", 
-      "src/cpp/ext/reflection.pb.cc"
+      "src/cpp/ext/proto_server_reflection_plugin.cc"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -4387,6 +4465,18 @@
   {
     "deps": [], 
     "headers": [
+      "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h", 
+      "src/proto/grpc/reflection/v1alpha/reflection.pb.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++_reflection_codegen", 
+    "src": [], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [], 
+    "headers": [
       "test/cpp/util/test_config.h"
     ], 
     "language": "c++", 
@@ -4405,7 +4495,8 @@
       "grpc++_codegen_base_src", 
       "grpc++_codegen_proto", 
       "grpc++_config_proto", 
-      "grpc_test_util"
+      "grpc_test_util", 
+      "thrift_util"
     ], 
     "headers": [
       "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h", 
@@ -4460,19 +4551,31 @@
   {
     "deps": [
       "grpc++", 
-      "grpc_plugin_support"
+      "grpc++_reflection", 
+      "grpc++_test_config"
     ], 
     "headers": [
       "test/cpp/util/cli_call.h", 
-      "test/cpp/util/proto_file_parser.h"
+      "test/cpp/util/cli_credentials.h", 
+      "test/cpp/util/config_grpc_cli.h", 
+      "test/cpp/util/grpc_tool.h", 
+      "test/cpp/util/proto_file_parser.h", 
+      "test/cpp/util/proto_reflection_descriptor_database.h"
     ], 
     "language": "c++", 
     "name": "grpc_cli_libs", 
     "src": [
       "test/cpp/util/cli_call.cc", 
       "test/cpp/util/cli_call.h", 
+      "test/cpp/util/cli_credentials.cc", 
+      "test/cpp/util/cli_credentials.h", 
+      "test/cpp/util/config_grpc_cli.h", 
+      "test/cpp/util/grpc_tool.cc", 
+      "test/cpp/util/grpc_tool.h", 
       "test/cpp/util/proto_file_parser.cc", 
-      "test/cpp/util/proto_file_parser.h"
+      "test/cpp/util/proto_file_parser.h", 
+      "test/cpp/util/proto_reflection_descriptor_database.cc", 
+      "test/cpp/util/proto_reflection_descriptor_database.h"
     ], 
     "third_party": false, 
     "type": "lib"
@@ -4617,7 +4720,7 @@
       "src/proto/grpc/testing/test.pb.h"
     ], 
     "language": "c++", 
-    "name": "interop_server_main", 
+    "name": "interop_server_lib", 
     "src": [
       "test/cpp/interop/interop_server.cc"
     ], 
@@ -4626,6 +4729,19 @@
   }, 
   {
     "deps": [
+      "interop_server_lib"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "interop_server_main", 
+    "src": [
+      "test/cpp/interop/interop_server_bootstrap.cc"
+    ], 
+    "third_party": false, 
+    "type": "lib"
+  }, 
+  {
+    "deps": [
       "grpc++", 
       "grpc++_test_util", 
       "grpc_test_util"
@@ -5372,6 +5488,7 @@
       "test/core/end2end/tests/default_host.c", 
       "test/core/end2end/tests/disappearing_server.c", 
       "test/core/end2end/tests/empty_batch.c", 
+      "test/core/end2end/tests/filter_call_init_fails.c", 
       "test/core/end2end/tests/filter_causes_close.c", 
       "test/core/end2end/tests/graceful_server_shutdown.c", 
       "test/core/end2end/tests/high_initial_seqno.c", 
@@ -5379,6 +5496,7 @@
       "test/core/end2end/tests/idempotent_request.c", 
       "test/core/end2end/tests/invoke_large_request.c", 
       "test/core/end2end/tests/large_metadata.c", 
+      "test/core/end2end/tests/load_reporting_hook.c", 
       "test/core/end2end/tests/max_concurrent_streams.c", 
       "test/core/end2end/tests/max_message_length.c", 
       "test/core/end2end/tests/negative_deadline.c", 
@@ -5432,6 +5550,7 @@
       "test/core/end2end/tests/default_host.c", 
       "test/core/end2end/tests/disappearing_server.c", 
       "test/core/end2end/tests/empty_batch.c", 
+      "test/core/end2end/tests/filter_call_init_fails.c", 
       "test/core/end2end/tests/filter_causes_close.c", 
       "test/core/end2end/tests/graceful_server_shutdown.c", 
       "test/core/end2end/tests/high_initial_seqno.c", 
@@ -5439,6 +5558,7 @@
       "test/core/end2end/tests/idempotent_request.c", 
       "test/core/end2end/tests/invoke_large_request.c", 
       "test/core/end2end/tests/large_metadata.c", 
+      "test/core/end2end/tests/load_reporting_hook.c", 
       "test/core/end2end/tests/max_concurrent_streams.c", 
       "test/core/end2end/tests/max_message_length.c", 
       "test/core/end2end/tests/negative_deadline.c", 
@@ -5471,11 +5591,13 @@
     "headers": [
       "include/grpc/census.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/grpc_filter.h", 
       "src/core/ext/census/mlog.h", 
+      "src/core/ext/census/resource.h", 
       "src/core/ext/census/rpc_metric_id.h"
     ], 
     "language": "c", 
@@ -5483,6 +5605,8 @@
     "src": [
       "include/grpc/census.h", 
       "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", 
@@ -5497,6 +5621,8 @@
       "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/tracing.c"
     ], 
@@ -5697,6 +5823,7 @@
       "src/core/lib/channel/compress_filter.h", 
       "src/core/lib/channel/connected_channel.h", 
       "src/core/lib/channel/context.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/compression/algorithm_metadata.h", 
@@ -5767,6 +5894,7 @@
       "src/core/lib/transport/metadata.h", 
       "src/core/lib/transport/metadata_batch.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"
     ], 
@@ -5791,6 +5919,8 @@
       "src/core/lib/channel/connected_channel.c", 
       "src/core/lib/channel/connected_channel.h", 
       "src/core/lib/channel/context.h", 
+      "src/core/lib/channel/handshaker.c", 
+      "src/core/lib/channel/handshaker.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", 
@@ -5941,6 +6071,8 @@
       "src/core/lib/transport/metadata_batch.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", 
@@ -6049,12 +6181,15 @@
       "nanopb"
     ], 
     "headers": [
+      "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"
     ], 
     "language": "c", 
     "name": "grpc_lb_policy_grpclb", 
     "src": [
+      "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", 
@@ -6298,7 +6433,6 @@
       "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/timeout_encoding.h", 
       "src/core/ext/transport/chttp2/transport/varint.h"
     ], 
     "language": "c", 
@@ -6342,8 +6476,6 @@
       "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/timeout_encoding.c", 
-      "src/core/ext/transport/chttp2/transport/timeout_encoding.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"
@@ -6552,6 +6684,7 @@
       "include/grpc++/support/sync_stream.h", 
       "include/grpc++/support/time.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"
     ], 
@@ -6615,6 +6748,8 @@
       "src/cpp/client/generic_stub.cc", 
       "src/cpp/client/insecure_credentials.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", 
       "src/cpp/common/core_codegen.cc", 
       "src/cpp/common/rpc_method.cc", 
@@ -6752,5 +6887,41 @@
     ], 
     "third_party": false, 
     "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "grpc++_codegen_proto"
+    ], 
+    "headers": [
+      "include/grpc++/ext/reflection.grpc.pb.h", 
+      "include/grpc++/ext/reflection.pb.h"
+    ], 
+    "language": "c++", 
+    "name": "grpc++_reflection_proto", 
+    "src": [
+      "include/grpc++/ext/reflection.grpc.pb.h", 
+      "include/grpc++/ext/reflection.pb.h", 
+      "src/cpp/ext/reflection.grpc.pb.cc", 
+      "src/cpp/ext/reflection.pb.cc"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "grpc++_codegen_base"
+    ], 
+    "headers": [
+      "include/grpc++/impl/codegen/thrift_serializer.h", 
+      "include/grpc++/impl/codegen/thrift_utils.h"
+    ], 
+    "language": "c++", 
+    "name": "thrift_util", 
+    "src": [
+      "include/grpc++/impl/codegen/thrift_serializer.h", 
+      "include/grpc++/impl/codegen/thrift_utils.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
   }
 ]
diff --git a/tools/run_tests/task_runner.py b/tools/run_tests/task_runner.py
index b42aa17..2e3fa44 100755
--- a/tools/run_tests/task_runner.py
+++ b/tools/run_tests/task_runner.py
@@ -30,6 +30,8 @@
 
 """Runs selected gRPC test/build tasks."""
 
+from __future__ import print_function
+
 import argparse
 import atexit
 import jobset
@@ -111,7 +113,7 @@
 for target in targets:
   build_jobs.append(target.build_jobspec())
 if not build_jobs:
-  print 'Nothing to build.'
+  print('Nothing to build.')
   sys.exit(1)
 
 jobset.message('START', 'Building targets.', do_newline=True)
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index d94301b..b0c09ac 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -182,6 +182,27 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
+    "name": "census_resource_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
     "name": "channel_create_test", 
     "platforms": [
       "linux", 
@@ -2240,6 +2261,27 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "filter_end2end_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "generic_end2end_test", 
     "platforms": [
       "linux", 
@@ -2282,6 +2324,27 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "grpc_tool_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "grpclb_api_test", 
     "platforms": [
       "linux", 
@@ -2301,6 +2364,27 @@
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
     "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "grpclb_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
     "gtest": true, 
     "language": "c++", 
     "name": "hybrid_end2end_test", 
@@ -4678,6 +4762,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -4832,6 +4938,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -5558,6 +5686,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -5712,6 +5862,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -6424,6 +6596,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -6571,6 +6764,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -7190,6 +7404,26 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -7330,6 +7564,26 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -7978,6 +8232,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -8132,6 +8408,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -8774,6 +9072,22 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -8886,6 +9200,22 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -9498,6 +9828,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -9630,6 +9982,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -10060,7 +10434,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10082,7 +10456,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10104,7 +10478,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10126,7 +10500,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10148,7 +10522,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10170,7 +10544,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10192,7 +10566,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10214,7 +10588,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10236,7 +10610,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10258,7 +10632,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10280,7 +10654,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10302,7 +10676,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10324,7 +10698,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10346,7 +10720,29 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10368,7 +10764,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10390,7 +10786,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10412,7 +10808,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10434,7 +10830,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10456,7 +10852,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10478,7 +10874,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10500,7 +10896,29 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10522,7 +10940,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10544,7 +10962,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10566,7 +10984,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10588,7 +11006,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10610,7 +11028,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10632,7 +11050,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10654,7 +11072,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10676,7 +11094,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10698,7 +11116,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10720,7 +11138,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10742,7 +11160,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10764,7 +11182,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10786,7 +11204,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10808,7 +11226,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10830,7 +11248,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10852,7 +11270,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10874,7 +11292,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10896,7 +11314,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -10918,7 +11336,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_test", 
+    "name": "h2_load_reporting_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -11222,6 +11640,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -11369,6 +11808,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -12020,6 +12480,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -12146,6 +12627,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_message_length"
     ], 
     "ci_platforms": [
@@ -12713,6 +13215,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -12860,6 +13383,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -13448,6 +13992,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -13574,6 +14139,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -14162,6 +14748,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -14309,6 +14916,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -14974,6 +15602,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -15128,6 +15778,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -15854,6 +16526,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_cert_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -16008,6 +16702,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_cert_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -16678,6 +17394,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -16804,6 +17541,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_message_length"
     ], 
     "ci_platforms": [
@@ -17400,6 +18158,26 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -17540,6 +18318,26 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -18206,6 +19004,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -18360,6 +19180,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -19064,6 +19906,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -19218,6 +20082,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -19836,6 +20722,26 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -19976,6 +20882,26 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -20602,6 +21528,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -20756,6 +21704,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -21382,6 +22352,22 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -21494,6 +22480,22 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -22084,6 +23086,28 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -22216,6 +23240,28 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -22646,7 +23692,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22668,7 +23714,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22690,7 +23736,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22712,7 +23758,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22734,7 +23780,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22756,7 +23802,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22778,7 +23824,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22800,7 +23846,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22822,7 +23868,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22844,7 +23890,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22866,7 +23912,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22888,7 +23934,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22910,7 +23956,29 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22932,7 +24000,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22954,7 +24022,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22976,7 +24044,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -22998,7 +24066,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23020,7 +24088,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23042,7 +24110,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23064,7 +24132,29 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23086,7 +24176,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23108,7 +24198,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23130,7 +24220,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23152,7 +24242,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23174,7 +24264,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23196,7 +24286,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23218,7 +24308,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23240,7 +24330,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23262,7 +24352,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23284,7 +24374,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23306,7 +24396,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23328,7 +24418,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23350,7 +24440,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23372,7 +24462,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23394,7 +24484,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23416,7 +24506,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23438,7 +24528,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23460,7 +24550,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23482,7 +24572,7 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
-    "name": "h2_loadreporting_nosec_test", 
+    "name": "h2_load_reporting_nosec_test", 
     "platforms": [
       "windows", 
       "linux", 
@@ -23723,6 +24813,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -23849,6 +24960,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_message_length"
     ], 
     "ci_platforms": [
@@ -24395,6 +25527,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -24542,6 +25695,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -25109,6 +26283,27 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -25235,6 +26430,27 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -25822,6 +27038,29 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [
+      "msan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -25983,6 +27222,29 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [
+      "msan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
@@ -26614,6 +27876,26 @@
   }, 
   {
     "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "filter_causes_close"
     ], 
     "ci_platforms": [
@@ -26754,6 +28036,26 @@
   }, 
   {
     "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "max_concurrent_streams"
     ], 
     "ci_platforms": [
diff --git a/vsprojects/README.md b/vsprojects/README.md
index b95b468..56d9f56 100644
--- a/vsprojects/README.md
+++ b/vsprojects/README.md
@@ -89,3 +89,18 @@
 2. Open solution `third_party\protobuf\cmake\protobuf.sln` and build it in Release mode. That will build libraries `libprotobuf.lib` and `libprotoc.lib` needed for the next step.
 
 3. Open solution `vsprojects\grpc_protoc_plugins.sln` and build it in Release mode. As a result, you should obtain a set of gRPC protoc plugin binaries (`grpc_cpp_plugin.exe`, `grpc_csharp_plugin.exe`, ...)
+
+#Building using CMake (with BoringSSL)
+1. Install [Active State Perl](http://www.activestate.com/activeperl/) (`choco install activeperl`)
+2. Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
+2. Install [Go](https://golang.org/dl/) (`choco install golang`)
+3. Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`)
+4. Update boringssl sumbodule to `master`
+5. Run this commads in grpc directory:
+```
+> md .build
+> cd .build
+> call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x64
+> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
+> cmake --build .
+```
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 7232440..c28f3ba 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -109,6 +109,17 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_resource_test", "vcxproj\test\census_resource_test\census_resource_test.vcxproj", "{18CF99B5-3C61-EC3D-9509-3C95334C3B88}"
+	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}") = "channel_create_test", "vcxproj\test\channel_create_test\channel_create_test.vcxproj", "{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -748,7 +759,7 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_loadreporting_nosec_test", "vcxproj\test/end2end/fixtures\h2_loadreporting_nosec_test\h2_loadreporting_nosec_test.vcxproj", "{679EA55C-7399-53E8-79F0-82FBDB3DDE07}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_load_reporting_nosec_test", "vcxproj\test/end2end/fixtures\h2_load_reporting_nosec_test\h2_load_reporting_nosec_test.vcxproj", "{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -760,7 +771,7 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_loadreporting_test", "vcxproj\test/end2end/fixtures\h2_loadreporting_test\h2_loadreporting_test.vcxproj", "{B107130E-EA33-C114-9CB6-78A18C929F64}"
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_load_reporting_test", "vcxproj\test/end2end/fixtures\h2_load_reporting_test\h2_load_reporting_test.vcxproj", "{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
 	EndProjectSection
@@ -1599,6 +1610,22 @@
 		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|Win32.Build.0 = Release|Win32
 		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.ActiveCfg = Release|x64
 		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.Build.0 = Release|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|Win32.ActiveCfg = Debug|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|x64.ActiveCfg = Debug|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release|Win32.ActiveCfg = Release|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release|x64.ActiveCfg = Release|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|Win32.Build.0 = Debug|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug|x64.Build.0 = Debug|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release|Win32.Build.0 = Release|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release|x64.Build.0 = Release|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Debug-DLL|x64.Build.0 = Debug|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release-DLL|Win32.Build.0 = Release|Win32
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release-DLL|x64.ActiveCfg = Release|x64
+		{18CF99B5-3C61-EC3D-9509-3C95334C3B88}.Release-DLL|x64.Build.0 = Release|x64
 		{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}.Debug|x64.ActiveCfg = Debug|x64
 		{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}.Release|Win32.ActiveCfg = Release|Win32
@@ -2607,38 +2634,38 @@
 		{EEBEFA75-C625-C823-FE96-9AD64887B57D}.Release-DLL|Win32.Build.0 = Release|Win32
 		{EEBEFA75-C625-C823-FE96-9AD64887B57D}.Release-DLL|x64.ActiveCfg = Release|x64
 		{EEBEFA75-C625-C823-FE96-9AD64887B57D}.Release-DLL|x64.Build.0 = Release|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug|Win32.ActiveCfg = Debug|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug|x64.ActiveCfg = Debug|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release|Win32.ActiveCfg = Release|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release|x64.ActiveCfg = Release|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug|Win32.Build.0 = Debug|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug|x64.Build.0 = Debug|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release|Win32.Build.0 = Release|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release|x64.Build.0 = Release|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Debug-DLL|x64.Build.0 = Debug|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release-DLL|Win32.Build.0 = Release|Win32
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release-DLL|x64.ActiveCfg = Release|x64
-		{679EA55C-7399-53E8-79F0-82FBDB3DDE07}.Release-DLL|x64.Build.0 = Release|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug|Win32.ActiveCfg = Debug|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug|x64.ActiveCfg = Debug|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release|Win32.ActiveCfg = Release|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release|x64.ActiveCfg = Release|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug|Win32.Build.0 = Debug|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug|x64.Build.0 = Debug|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release|Win32.Build.0 = Release|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release|x64.Build.0 = Release|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Debug-DLL|x64.Build.0 = Debug|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release-DLL|Win32.Build.0 = Release|Win32
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release-DLL|x64.ActiveCfg = Release|x64
-		{B107130E-EA33-C114-9CB6-78A18C929F64}.Release-DLL|x64.Build.0 = Release|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug|x64.ActiveCfg = Debug|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release|Win32.ActiveCfg = Release|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release|x64.ActiveCfg = Release|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug|Win32.Build.0 = Debug|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug|x64.Build.0 = Debug|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release|Win32.Build.0 = Release|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release|x64.Build.0 = Release|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Debug-DLL|x64.Build.0 = Debug|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release-DLL|Win32.Build.0 = Release|Win32
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release-DLL|x64.ActiveCfg = Release|x64
+		{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}.Release-DLL|x64.Build.0 = Release|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug|x64.ActiveCfg = Debug|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release|Win32.ActiveCfg = Release|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release|x64.ActiveCfg = Release|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug|Win32.Build.0 = Debug|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug|x64.Build.0 = Debug|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release|Win32.Build.0 = Release|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release|x64.Build.0 = Release|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Debug-DLL|x64.Build.0 = Debug|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release-DLL|Win32.Build.0 = Release|Win32
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release-DLL|x64.ActiveCfg = Release|x64
+		{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}.Release-DLL|x64.Build.0 = Release|x64
 		{0F761FF3-342A-C429-711F-F76181BAA52D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{0F761FF3-342A-C429-711F-F76181BAA52D}.Debug|x64.ActiveCfg = Debug|x64
 		{0F761FF3-342A-C429-711F-F76181BAA52D}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index c50fc4a..321a403 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -370,6 +370,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\secure_auth_context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\channel_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
@@ -378,6 +379,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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\compression\algorithm_metadata.h" />
@@ -448,6 +450,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
   </ItemGroup>
@@ -482,6 +485,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_filter.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
@@ -526,6 +531,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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">
@@ -686,6 +693,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index a68ac33..b34ca03 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -46,6 +46,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_filter.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
@@ -112,6 +115,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -352,6 +358,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -695,6 +704,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\channel_filter.h">
+      <Filter>src\cpp\common</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
@@ -719,6 +731,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -929,6 +944,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_reflection_codegen/grpc++_reflection_codegen.vcxproj b/vsprojects/vcxproj/grpc++_reflection_codegen/grpc++_reflection_codegen.vcxproj
new file mode 100644
index 0000000..d9e10c2
--- /dev/null
+++ b/vsprojects/vcxproj/grpc++_reflection_codegen/grpc++_reflection_codegen.vcxproj
@@ -0,0 +1,168 @@
+<?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>{C8A925BF-4373-D85D-60AE-96CDCBBF33F2}</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>grpc++_reflection_codegen</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>grpc++_reflection_codegen</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>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\reflection\v1alpha\reflection.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\reflection\v1alpha\reflection.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\reflection\v1alpha\reflection.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\reflection\v1alpha\reflection.grpc.pb.h">
+    </ClInclude>
+  </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/grpc++_reflection_codegen/grpc++_reflection_codegen.vcxproj.filters b/vsprojects/vcxproj/grpc++_reflection_codegen/grpc++_reflection_codegen.vcxproj.filters
new file mode 100644
index 0000000..577dcc7
--- /dev/null
+++ b/vsprojects/vcxproj/grpc++_reflection_codegen/grpc++_reflection_codegen.vcxproj.filters
@@ -0,0 +1,27 @@
+<?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\reflection\v1alpha\reflection.proto">
+      <Filter>src\proto\grpc\reflection\v1alpha</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{d6f45d49-92db-00f7-3dd4-e53f5768d80c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{32b951f4-cef1-24a3-ffb9-bb229f0cdd6a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{8fdcb9f3-4d86-2f49-5c15-c92e0e0f4fba}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\reflection">
+      <UniqueIdentifier>{098a074c-f3de-2840-8009-1a3840af1efc}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\reflection\v1alpha">
+      <UniqueIdentifier>{219ff371-7d3a-130c-5792-be36514a4e98}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
index d0fca9b..c2c7d00 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
@@ -200,6 +200,8 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_serializer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_utils.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.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 cc98c60..9b8c8dd 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
@@ -192,6 +192,12 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_serializer.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\thrift_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.h">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 3a4aa13..a7bb3ef 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -366,6 +366,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\channel_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
@@ -374,6 +375,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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\compression\algorithm_metadata.h" />
@@ -444,6 +446,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
   </ItemGroup>
@@ -468,6 +471,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_filter.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\core_codegen.cc">
@@ -512,6 +517,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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">
@@ -672,6 +679,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 56b4344..4ad0ae3 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -31,6 +31,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_filter.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\completion_queue.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
@@ -97,6 +100,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -337,6 +343,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -668,6 +677,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\cpp\common\channel_filter.h">
+      <Filter>src\cpp\common</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
@@ -692,6 +704,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -902,6 +917,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 51f2107..2527047 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -305,6 +305,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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\compression\algorithm_metadata.h" />
@@ -375,6 +376,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.h" />
@@ -396,7 +398,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\security\context\security_context.h" />
@@ -439,6 +440,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
@@ -448,11 +450,13 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h" />
   </ItemGroup>
   <ItemGroup>
@@ -468,6 +472,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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">
@@ -628,6 +634,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
@@ -672,8 +680,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
@@ -784,6 +790,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
@@ -806,6 +814,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
@@ -824,6 +834,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 497111f..1fdf0f5 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -19,6 +19,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -259,6 +262,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -325,9 +331,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
@@ -493,6 +496,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
       <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
       <Filter>src\core\ext\lb_policy\grpclb</Filter>
     </ClCompile>
@@ -526,6 +532,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
       <Filter>src\core\ext\load_reporting</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
+      <Filter>src\core\ext\census</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
@@ -553,6 +562,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
+      <Filter>src\core\ext\census</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
@@ -671,6 +683,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -881,6 +896,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
@@ -944,9 +962,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
@@ -1073,6 +1088,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h">
+      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
       <Filter>src\core\ext\lb_policy\grpclb</Filter>
     </ClInclude>
@@ -1100,6 +1118,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h">
+      <Filter>src\core\ext\census</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
@@ -1115,6 +1136,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h">
+      <Filter>src\core\ext\census</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj
index 39cb1e0..425b66f 100644
--- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj
+++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj
@@ -148,20 +148,33 @@
 
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\config_grpc_cli.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_reflection_descriptor_database.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_call.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_reflection_descriptor_database.cc">
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj">
+      <Project>{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
       <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_plugin_support\grpc_plugin_support.vcxproj">
-      <Project>{B6E81D84-2ACB-41B8-8781-493A944C7817}</Project>
+    <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" />
diff --git a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters
index 55ef18b..b2128c2 100644
--- a/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_cli_libs/grpc_cli_libs.vcxproj.filters
@@ -4,17 +4,38 @@
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_call.cc">
       <Filter>test\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.cc">
       <Filter>test\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\proto_reflection_descriptor_database.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_call.h">
       <Filter>test\cpp\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_credentials.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\config_grpc_cli.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\grpc_tool.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_file_parser.h">
       <Filter>test\cpp\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\proto_reflection_descriptor_database.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index f0a8f7b..80dd6b2 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -147,6 +147,36 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <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\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+  </ItemGroup>
+  <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\security\oauth2_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\cq_verifier.h" />
@@ -160,6 +190,86 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\port_server_client.h" />
     <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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\compression\algorithm_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
+    <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\surface\api_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\data\client_certs.c">
@@ -196,6 +306,184 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
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 a1d31eb..8dc28d1 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -52,6 +52,359 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\util\slice_splitter.c">
       <Filter>test\core\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+      <Filter>src\core\lib\debug</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.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>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\test\core\end2end\data\ssl_test_data.h">
@@ -93,9 +446,294 @@
     <ClInclude Include="$(SolutionDir)\..\test\core\util\slice_splitter.h">
       <Filter>test\core\util</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
+      <Filter>src\core\lib\debug</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{50129440-aff7-7df7-682c-b9671be19a6f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc">
+      <UniqueIdentifier>{d448b078-95a6-6fca-fe4a-8b44dd71f359}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{314a6801-6fe3-9211-33d8-ecf3332c1151}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{8e97f1e1-f4d1-a56e-0837-7901778fb3b9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src">
+      <UniqueIdentifier>{7d107d7c-1da3-9525-3ba1-3a411b552ea8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core">
+      <UniqueIdentifier>{f7bfac91-5eb2-dea7-4601-6c63edbbf997}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib">
+      <UniqueIdentifier>{f4e8c61e-1ca6-0fdd-7b5e-b7f9a30c9a21}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\channel">
+      <UniqueIdentifier>{1cd1503c-bec0-5ade-c75f-aa25c80975ec}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\compression">
+      <UniqueIdentifier>{09632582-2cc3-5618-d673-65d3884f8ce5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\debug">
+      <UniqueIdentifier>{2c1a72e9-886e-8082-9d2f-0fc9cb3ab996}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\http">
+      <UniqueIdentifier>{4862ecce-fa07-eb5e-5c05-bfa753c8bfe5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\iomgr">
+      <UniqueIdentifier>{fc7f488e-08b4-8366-3720-1f7ffaa0b0b3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\json">
+      <UniqueIdentifier>{89bc8f83-e29a-ddab-8f6b-22df11cdc867}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\surface">
+      <UniqueIdentifier>{7f2b7dca-395f-94dd-c9ad-9a286bd9751e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\transport">
+      <UniqueIdentifier>{5249e884-ea07-6782-531d-ec622c54b9af}</UniqueIdentifier>
+    </Filter>
     <Filter Include="test">
       <UniqueIdentifier>{a2783de3-4fcf-718d-a859-c2108350ff33}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 5752dd2..fffb409 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -295,6 +295,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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\compression\algorithm_metadata.h" />
@@ -365,6 +366,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\bin_decoder.h" />
@@ -386,7 +388,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\status_conversion.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel.h" />
@@ -407,6 +408,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" />
@@ -414,11 +416,13 @@
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_decode.h" />
     <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb_encode.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h" />
   </ItemGroup>
   <ItemGroup>
@@ -436,6 +440,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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">
@@ -596,6 +602,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
@@ -642,8 +650,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\writing.c">
@@ -700,6 +706,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c">
@@ -714,6 +722,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\round_robin\round_robin.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
@@ -732,6 +742,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index d031a3d..8c8afb6 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -22,6 +22,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
       <Filter>src\core\lib\channel</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -262,6 +265,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
       <Filter>src\core\lib\transport</Filter>
     </ClCompile>
@@ -331,9 +337,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.c">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.c">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClCompile>
@@ -418,6 +421,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.c">
       <Filter>src\core\ext\load_reporting</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.c">
+      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c">
       <Filter>src\core\ext\lb_policy\grpclb</Filter>
     </ClCompile>
@@ -439,6 +445,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\round_robin\round_robin.c">
       <Filter>src\core\ext\lb_policy\round_robin</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\base_resources.c">
+      <Filter>src\core\ext\census</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\context.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
@@ -466,6 +475,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\placeholders.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\resource.c">
+      <Filter>src\core\ext\census</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\tracing.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
@@ -581,6 +593,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
       <Filter>src\core\lib\channel</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.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>
@@ -791,6 +806,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
       <Filter>src\core\lib\transport</Filter>
     </ClInclude>
@@ -854,9 +872,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\stream_map.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\timeout_encoding.h">
-      <Filter>src\core\ext\transport\chttp2\transport</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\transport\varint.h">
       <Filter>src\core\ext\transport\chttp2\transport</Filter>
     </ClInclude>
@@ -917,6 +932,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting_filter.h">
       <Filter>src\core\ext\load_reporting</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h">
+      <Filter>src\core\ext\lb_policy\grpclb</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h">
       <Filter>src\core\ext\lb_policy\grpclb</Filter>
     </ClInclude>
@@ -938,6 +956,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\aggregation.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\base_resources.h">
+      <Filter>src\core\ext\census</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
@@ -953,6 +974,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h">
+      <Filter>src\core\ext\census</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\rpc_metric_id.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj b/vsprojects/vcxproj/interop_server_lib/interop_server_lib.vcxproj
similarity index 63%
copy from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
copy to vsprojects/vcxproj/interop_server_lib/interop_server_lib.vcxproj
index 2076548..204d3f7 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
+++ b/vsprojects/vcxproj/interop_server_lib/interop_server_lib.vcxproj
@@ -1,6 +1,5 @@
 <?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>
@@ -20,7 +19,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{B107130E-EA33-C114-9CB6-78A18C929F64}</ProjectGuid>
+    <ProjectGuid>{458DCA09-83B9-5E68-D7E9-118864ECBD94}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -38,12 +37,12 @@
     <PlatformToolset>v140</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
-    <ConfigurationType>Application</ConfigurationType>
+    <ConfigurationType>StaticLibrary</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
@@ -54,24 +53,14 @@
   <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>h2_loadreporting_test</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>
+    <TargetName>interop_server_lib</TargetName>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>h2_loadreporting_test</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>
+    <TargetName>interop_server_lib</TargetName>
   </PropertyGroup>
     <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
@@ -86,7 +75,7 @@
       <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
     </ClCompile>
     <Link>
-      <SubSystem>Console</SubSystem>
+      <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
       <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
     </Link>
@@ -105,7 +94,7 @@
       <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
     </ClCompile>
     <Link>
-      <SubSystem>Console</SubSystem>
+      <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
       <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
     </Link>
@@ -126,7 +115,7 @@
       <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
     </ClCompile>
     <Link>
-      <SubSystem>Console</SubSystem>
+      <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
       <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -149,7 +138,7 @@
       <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
     </ClCompile>
     <Link>
-      <SubSystem>Console</SubSystem>
+      <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
       <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -158,16 +147,46 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <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\interop_server.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
-      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\interop_server_helper\interop_server_helper.vcxproj">
+      <Project>{F55BEA2C-B61D-AAFE-CA15-223B8AC0DE5A}</Project>
+    </ProjectReference>
+    <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>
@@ -177,26 +196,17 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
       <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
     </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="packages.config" />
+    <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">
-  <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/interop_server_lib/interop_server_lib.vcxproj.filters b/vsprojects/vcxproj/interop_server_lib/interop_server_lib.vcxproj.filters
new file mode 100644
index 0000000..63fc0f7
--- /dev/null
+++ b/vsprojects/vcxproj/interop_server_lib/interop_server_lib.vcxproj.filters
@@ -0,0 +1,42 @@
+<?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\interop_server.cc">
+      <Filter>test\cpp\interop</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{356c90d7-2dcd-5f6a-d3ca-6461f2597581}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{70740334-0cbf-ab29-0e1c-f0ffa390d77f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{d581eb6c-94b6-eb79-6b76-d122c13cff3c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\testing">
+      <UniqueIdentifier>{27f43e87-cfd9-68cc-179a-fc44046797c4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{3402c01e-a9f6-2dd8-6963-03a5774d37f2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{656eed4b-782e-224c-6101-8a61c2daa94e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\interop">
+      <UniqueIdentifier>{61c0dab5-5c69-82b0-2961-4104445f2e06}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj
index 18971d6..9fd4d11 100644
--- a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj
+++ b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj
@@ -147,57 +147,12 @@
   </ItemDefinitionGroup>
 
   <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\interop_server.cc">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\interop_server_bootstrap.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\interop_server_helper\interop_server_helper.vcxproj">
-      <Project>{F55BEA2C-B61D-AAFE-CA15-223B8AC0DE5A}</Project>
-    </ProjectReference>
-    <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\.\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>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_config\grpc++_test_config.vcxproj">
-      <Project>{3F7D093D-11F9-C4BC-BEB7-18EB28E3F290}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\interop_server_lib\interop_server_lib.vcxproj">
+      <Project>{458DCA09-83B9-5E68-D7E9-118864ECBD94}</Project>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters
index 4ee8135..d8d0492 100644
--- a/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters
+++ b/vsprojects/vcxproj/interop_server_main/interop_server_main.vcxproj.filters
@@ -1,33 +1,12 @@
 <?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\interop_server.cc">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\interop\interop_server_bootstrap.cc">
       <Filter>test\cpp\interop</Filter>
     </ClCompile>
   </ItemGroup>
 
   <ItemGroup>
-    <Filter Include="src">
-      <UniqueIdentifier>{9dfb04b3-9e58-7efb-70a2-b02ec8c5e83e}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\proto">
-      <UniqueIdentifier>{ebd8177f-6130-a4fb-1c41-d894f801e3b9}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\proto\grpc">
-      <UniqueIdentifier>{1df1acf2-4654-4530-10af-912381c69012}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="src\proto\grpc\testing">
-      <UniqueIdentifier>{ba56d830-1546-c07f-f5ee-03164e41914e}</UniqueIdentifier>
-    </Filter>
     <Filter Include="test">
       <UniqueIdentifier>{02523054-816a-75a0-b24b-f527e99c7142}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj b/vsprojects/vcxproj/test/census_resource_test/census_resource_test.vcxproj
similarity index 95%
copy from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
copy to vsprojects/vcxproj/test/census_resource_test/census_resource_test.vcxproj
index 2076548..c4fbd54 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
+++ b/vsprojects/vcxproj/test/census_resource_test/census_resource_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{B107130E-EA33-C114-9CB6-78A18C929F64}</ProjectGuid>
+    <ProjectGuid>{18CF99B5-3C61-EC3D-9509-3C95334C3B88}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -60,14 +60,14 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_loadreporting_test</TargetName>
+    <TargetName>census_resource_test</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>h2_loadreporting_test</TargetName>
+    <TargetName>census_resource_test</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>
@@ -158,13 +158,10 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\census\resource_test.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
-      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</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/census_resource_test/census_resource_test.vcxproj.filters b/vsprojects/vcxproj/test/census_resource_test/census_resource_test.vcxproj.filters
new file mode 100644
index 0000000..93faac5
--- /dev/null
+++ b/vsprojects/vcxproj/test/census_resource_test/census_resource_test.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\census\resource_test.c">
+      <Filter>test\core\census</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{313aad4e-d33b-88c5-7d94-e04a4cb0c912}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{ff2d74ef-228a-1739-7fa7-7dccbec5b0c5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\census">
+      <UniqueIdentifier>{4f529bd9-396f-027c-bc49-f9a6bbc97c72}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_nosec_test/h2_loadreporting_nosec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_nosec_test/h2_load_reporting_nosec_test.vcxproj
similarity index 98%
rename from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_nosec_test/h2_loadreporting_nosec_test.vcxproj
rename to vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_nosec_test/h2_load_reporting_nosec_test.vcxproj
index 6a6ac5e..1ccc6bb 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_nosec_test/h2_loadreporting_nosec_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_nosec_test/h2_load_reporting_nosec_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{679EA55C-7399-53E8-79F0-82FBDB3DDE07}</ProjectGuid>
+    <ProjectGuid>{4B9EBBAE-D838-EC09-0B10-2D4520FBC0FF}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -60,14 +60,14 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_loadreporting_nosec_test</TargetName>
+    <TargetName>h2_load_reporting_nosec_test</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>h2_loadreporting_nosec_test</TargetName>
+    <TargetName>h2_load_reporting_nosec_test</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>
@@ -158,7 +158,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_load_reporting.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_nosec_test/h2_load_reporting_nosec_test.vcxproj.filters
similarity index 68%
rename from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj.filters
rename to vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_nosec_test/h2_load_reporting_nosec_test.vcxproj.filters
index afe5432..72df23e 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_nosec_test/h2_load_reporting_nosec_test.vcxproj.filters
@@ -1,23 +1,23 @@
 <?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\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_load_reporting.c">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClCompile>
   </ItemGroup>
 
   <ItemGroup>
     <Filter Include="test">
-      <UniqueIdentifier>{8f73760a-74dc-05ef-65e1-fa8c44ccf918}</UniqueIdentifier>
+      <UniqueIdentifier>{abff9aef-586e-65d2-beb8-e6392ecf7440}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core">
-      <UniqueIdentifier>{a280079e-b626-333e-0636-8fe6eb788ca1}</UniqueIdentifier>
+      <UniqueIdentifier>{fd31cbf1-8cff-2e6a-618d-a01855997839}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{c1aa73d6-503a-06c0-42b2-0793a4805e96}</UniqueIdentifier>
+      <UniqueIdentifier>{c6cc113f-ddb4-733b-5c10-8f98aa2d7d22}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core\end2end\fixtures">
-      <UniqueIdentifier>{3e738e89-dc27-f929-cc8f-1aa94c24345b}</UniqueIdentifier>
+      <UniqueIdentifier>{2cd15a3b-a7e6-b847-b6c4-7c6cc03eacc2}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_test/h2_load_reporting_test.vcxproj
similarity index 98%
rename from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
rename to vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_test/h2_load_reporting_test.vcxproj
index 2076548..d5d1a15 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_test/h2_load_reporting_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{B107130E-EA33-C114-9CB6-78A18C929F64}</ProjectGuid>
+    <ProjectGuid>{F0A06723-2E3E-FE97-34B7-A2BA26D98B83}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -60,14 +60,14 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_loadreporting_test</TargetName>
+    <TargetName>h2_load_reporting_test</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>h2_loadreporting_test</TargetName>
+    <TargetName>h2_load_reporting_test</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>
@@ -158,7 +158,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_load_reporting.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_test/h2_load_reporting_test.vcxproj.filters
similarity index 68%
copy from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj.filters
copy to vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_test/h2_load_reporting_test.vcxproj.filters
index afe5432..95b049c 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_load_reporting_test/h2_load_reporting_test.vcxproj.filters
@@ -1,23 +1,23 @@
 <?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\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_load_reporting.c">
       <Filter>test\core\end2end\fixtures</Filter>
     </ClCompile>
   </ItemGroup>
 
   <ItemGroup>
     <Filter Include="test">
-      <UniqueIdentifier>{8f73760a-74dc-05ef-65e1-fa8c44ccf918}</UniqueIdentifier>
+      <UniqueIdentifier>{467ceaa9-3a51-d5df-0556-1ef8e91f5d7d}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core">
-      <UniqueIdentifier>{a280079e-b626-333e-0636-8fe6eb788ca1}</UniqueIdentifier>
+      <UniqueIdentifier>{1ec29254-9064-0338-78ca-94d8cfdbd95c}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{c1aa73d6-503a-06c0-42b2-0793a4805e96}</UniqueIdentifier>
+      <UniqueIdentifier>{58fc84e1-7dc9-a517-359e-7d7e1c417432}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core\end2end\fixtures">
-      <UniqueIdentifier>{3e738e89-dc27-f929-cc8f-1aa94c24345b}</UniqueIdentifier>
+      <UniqueIdentifier>{92ef09e0-592b-0ca5-4d79-5929ae159ed5}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_nosec_test/h2_loadreporting_nosec_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_nosec_test/h2_loadreporting_nosec_test.vcxproj.filters
deleted file mode 100644
index 4ed1bb0..0000000
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_nosec_test/h2_loadreporting_nosec_test.vcxproj.filters
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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\end2end\fixtures\h2_loadreporting.c">
-      <Filter>test\core\end2end\fixtures</Filter>
-    </ClCompile>
-  </ItemGroup>
-
-  <ItemGroup>
-    <Filter Include="test">
-      <UniqueIdentifier>{8adc89fb-e447-77bc-c462-3dba6abcf344}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core">
-      <UniqueIdentifier>{3c2c01f5-2a18-1bee-6ee0-217d415e2a95}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end">
-      <UniqueIdentifier>{3efa0f41-5802-6a8e-36ee-f246a201a1a5}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="test\core\end2end\fixtures">
-      <UniqueIdentifier>{366eb24f-49e9-d57f-e20f-729d1e0fb892}</UniqueIdentifier>
-    </Filter>
-  </ItemGroup>
-</Project>
-
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
index 28ced2d..a500fe3 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
@@ -179,6 +179,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\empty_batch.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_call_init_fails.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_causes_close.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\graceful_server_shutdown.c">
@@ -193,6 +195,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\large_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\load_reporting_hook.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_message_length.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
index 7c72535..6f2294c 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
@@ -43,6 +43,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\empty_batch.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_call_init_fails.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_causes_close.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
@@ -64,6 +67,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\large_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\load_reporting_hook.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
index bc064cd..7614089 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -181,6 +181,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\empty_batch.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_call_init_fails.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_causes_close.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\graceful_server_shutdown.c">
@@ -195,6 +197,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\large_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\load_reporting_hook.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_message_length.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
index d959c80..db336f0 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
@@ -46,6 +46,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\empty_batch.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_call_init_fails.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\filter_causes_close.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
@@ -67,6 +70,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\large_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\load_reporting_hook.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\max_concurrent_streams.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj b/vsprojects/vcxproj/test/filter_end2end_test/filter_end2end_test.vcxproj
similarity index 94%
copy from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
copy to vsprojects/vcxproj/test/filter_end2end_test/filter_end2end_test.vcxproj
index 2076548..99c000e 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
+++ b/vsprojects/vcxproj/test/filter_end2end_test/filter_end2end_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{B107130E-EA33-C114-9CB6-78A18C929F64}</ProjectGuid>
+    <ProjectGuid>{1D42975A-18A5-09D0-30B1-2AE6A97FB9DE}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -53,21 +53,23 @@
   </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\cpptest.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_loadreporting_test</TargetName>
+    <TargetName>filter_end2end_test</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>h2_loadreporting_test</TargetName>
+    <TargetName>filter_end2end_test</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>
@@ -158,16 +160,19 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\filter_end2end_test.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
-      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
+    <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>
diff --git a/vsprojects/vcxproj/test/filter_end2end_test/filter_end2end_test.vcxproj.filters b/vsprojects/vcxproj/test/filter_end2end_test/filter_end2end_test.vcxproj.filters
new file mode 100644
index 0000000..c684423
--- /dev/null
+++ b/vsprojects/vcxproj/test/filter_end2end_test/filter_end2end_test.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\cpp\end2end\filter_end2end_test.cc">
+      <Filter>test\cpp\end2end</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{f7581160-220d-1118-f29e-6b37e45671c9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{63784d35-03cc-1a7e-0c95-a9451bc1daf4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\end2end">
+      <UniqueIdentifier>{d2a01682-970e-d23d-1eb8-ef020e3a1ca3}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj b/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj
index cd844d1..78a0a63 100644
--- a/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj
+++ b/vsprojects/vcxproj/test/grpc_cli/grpc_cli.vcxproj
@@ -167,11 +167,8 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_cli_libs\grpc_cli_libs.vcxproj">
       <Project>{86E35862-43E8-F59E-F906-AFE0348AD3D2}</Project>
     </ProjectReference>
-    <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 Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj">
+      <Project>{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}</Project>
     </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
       <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
@@ -179,9 +176,6 @@
     <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>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
similarity index 65%
copy from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
copy to vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
index 2076548..c6f65aa 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
+++ b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{B107130E-EA33-C114-9CB6-78A18C929F64}</ProjectGuid>
+    <ProjectGuid>{F00D82D4-E988-6D2F-F0B9-9E82BCC2A2B2}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -53,21 +53,23 @@
   </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\cpptest.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_loadreporting_test</TargetName>
+    <TargetName>grpc_tool_test</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>h2_loadreporting_test</TargetName>
+    <TargetName>grpc_tool_test</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>
@@ -158,16 +160,98 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\create_auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <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\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool_test.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
-      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_cli_libs\grpc_cli_libs.vcxproj">
+      <Project>{86E35862-43E8-F59E-F906-AFE0348AD3D2}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj">
+      <Project>{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}</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>
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
new file mode 100644
index 0000000..731eb2e
--- /dev/null
+++ b/vsprojects/vcxproj/test/grpc_tool_test/grpc_tool_test.vcxproj.filters
@@ -0,0 +1,232 @@
+<?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\echo.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\echo_messages.proto">
+      <Filter>src\proto\grpc\testing</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\grpc_tool_test.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\create_auth_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.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>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="include">
+      <UniqueIdentifier>{89fed779-17c5-23da-c8a2-9e868ff34480}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc">
+      <UniqueIdentifier>{96e4a1a8-0b91-1a6d-ae4d-ddf33abb93c0}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++">
+      <UniqueIdentifier>{1d9dcc6f-7c1b-cdc3-4c35-73d5968dfd92}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl">
+      <UniqueIdentifier>{5eca7690-973a-c8ed-84d6-5325f8de43ac}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen">
+      <UniqueIdentifier>{5789073e-5b84-0ec9-af06-47866647874d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen\security">
+      <UniqueIdentifier>{d3f3293f-204f-7771-fcdf-de673f6b06b6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{7e90f37b-f9cc-0725-b2c1-12aa7d4809ba}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{7e4b71ef-8125-6446-bfc1-9bc90beed59c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src">
+      <UniqueIdentifier>{169774bd-5c6c-6827-66a4-326b4aef44d6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{1b609b37-ef2a-e5eb-e1ba-ad9e79c77438}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{cd1e35d8-8a61-62fe-6ce1-c8936872d1ef}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\testing">
+      <UniqueIdentifier>{f7ee4df5-1f47-1e7f-c91e-350382c1b729}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{f2166b83-6b0b-d53b-b58b-627bd9efcad2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{bbe36cbc-7fbe-2817-0bd0-d03726f323e6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\util">
+      <UniqueIdentifier>{e106cd7b-cfa0-0645-f1a9-2acedc23afe7}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
similarity index 91%
copy from vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
copy to vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
index 2076548..91b9a6e 100644
--- a/vsprojects/vcxproj/test/end2end/fixtures/h2_loadreporting_test/h2_loadreporting_test.vcxproj
+++ b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{B107130E-EA33-C114-9CB6-78A18C929F64}</ProjectGuid>
+    <ProjectGuid>{9D6FFE17-ABF0-A851-268E-9E3E8C573CBB}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -53,21 +53,23 @@
   </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\cpptest.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>h2_loadreporting_test</TargetName>
+    <TargetName>grpclb_test</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>h2_loadreporting_test</TargetName>
+    <TargetName>grpclb_test</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>
@@ -158,24 +160,35 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_loadreporting.c">
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.grpc.pb.cc">
+    </ClCompile>
+    <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\lb\v1\load_balancer.grpc.pb.h">
+    </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\grpclb\grpclb_test.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_tests\end2end_tests.vcxproj">
-      <Project>{1F1F9084-2A93-B80E-364F-5754894AFAB4}</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>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</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 Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
+    <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>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters
new file mode 100644
index 0000000..5493df2
--- /dev/null
+++ b/vsprojects/vcxproj/test/grpclb_test/grpclb_test.vcxproj.filters
@@ -0,0 +1,39 @@
+<?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\lb\v1\load_balancer.proto">
+      <Filter>src\proto\grpc\lb\v1</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\grpclb\grpclb_test.cc">
+      <Filter>test\cpp\grpclb</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{082bbcbc-bbd8-db7d-afe9-fa0fec76863d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto">
+      <UniqueIdentifier>{7c61995a-80c2-ef3d-0a4b-baf2221c12f8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc">
+      <UniqueIdentifier>{fc2920d4-902c-fdf0-d4b8-6b22e1361105}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\lb">
+      <UniqueIdentifier>{4778352a-559f-b008-e3d2-4ae9181260df}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\proto\grpc\lb\v1">
+      <UniqueIdentifier>{36a4326b-4f2a-4720-b730-e40fe078fd40}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test">
+      <UniqueIdentifier>{e0ba55a2-37d9-5029-6f4e-64f097307340}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{ad67d6ba-d08b-7879-2929-20f0f01c9918}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\grpclb">
+      <UniqueIdentifier>{4498fa30-2dab-584c-5711-a1055cec30f6}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj b/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj
index 37be682..76efe30 100644
--- a/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj
+++ b/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj
@@ -158,7 +158,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\transport\chttp2\timeout_encoding_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\transport\timeout_encoding_test.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj.filters b/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj.filters
index 3e3b8d2..d5fafc2 100644
--- a/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/timeout_encoding_test/timeout_encoding_test.vcxproj.filters
@@ -1,8 +1,8 @@
 <?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\transport\chttp2\timeout_encoding_test.c">
-      <Filter>test\core\transport\chttp2</Filter>
+    <ClCompile Include="$(SolutionDir)\..\test\core\transport\timeout_encoding_test.c">
+      <Filter>test\core\transport</Filter>
     </ClCompile>
   </ItemGroup>
 
@@ -16,9 +16,6 @@
     <Filter Include="test\core\transport">
       <UniqueIdentifier>{3178e0c5-5a68-26eb-6bf6-a5a8dabb0a3c}</UniqueIdentifier>
     </Filter>
-    <Filter Include="test\core\transport\chttp2">
-      <UniqueIdentifier>{40739011-4ce0-83f5-d2d6-af515bac7f87}</UniqueIdentifier>
-    </Filter>
   </ItemGroup>
 </Project>