Merge pull request #11098 from dgquintas/fix_subchannel_stuffs

Fixes to subchannel and its index
diff --git a/BUILD b/BUILD
index 0a188a8..3e54e87 100644
--- a/BUILD
+++ b/BUILD
@@ -33,13 +33,19 @@
 
 exports_files(["LICENSE"])
 
-package(default_visibility = ["//visibility:public"])
+package(
+    default_visibility = ["//visibility:public"],
+    features = [
+        "-layering_check",
+        "-parse_headers",
+    ],
+)
 
 load(
     "//bazel:grpc_build_system.bzl",
     "grpc_cc_library",
     "grpc_proto_plugin",
-    "grpc_cc_libraries",
+    "grpc_generate_one_off_targets",
 )
 
 # This should be updated along with build.yaml
@@ -58,48 +64,35 @@
     ],
 )
 
-grpc_cc_libraries(
+grpc_cc_library(
+    name = "grpc_unsecure",
     srcs = [
         "src/core/lib/surface/init.c",
-    ],
-    additional_dep_list = [
-        [
-            "grpc_secure",
-            "grpc_resolver_dns_ares",
-            "grpc_lb_policy_grpclb_secure",
-            "grpc_transport_chttp2_client_secure",
-            "grpc_transport_chttp2_server_secure",
-        ],
-        [],
-    ],
-    additional_src_list = [
-        [
-            "src/core/plugin_registry/grpc_plugin_registry.c",
-        ],
-        [
-            "src/core/lib/surface/init_unsecure.c",
-            "src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
-        ],
+        "src/core/lib/surface/init_unsecure.c",
+        "src/core/plugin_registry/grpc_unsecure_plugin_registry.c",
     ],
     language = "c",
-    name_list = [
-        "grpc",
-        "grpc_unsecure",
-    ],
     standalone = True,
     deps = [
-        "census",
-        "grpc_base",
-        "grpc_deadline_filter",
-        "grpc_lb_policy_pick_first",
-        "grpc_lb_policy_round_robin",
-        "grpc_load_reporting",
-        "grpc_max_age_filter",
-        "grpc_message_size_filter",
-        "grpc_resolver_dns_native",
-        "grpc_resolver_sockaddr",
-        "grpc_transport_chttp2_client_insecure",
-        "grpc_transport_chttp2_server_insecure",
+        "grpc_common",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc",
+    srcs = [
+        "src/core/lib/surface/init.c",
+        "src/core/plugin_registry/grpc_plugin_registry.c",
+    ],
+    language = "c",
+    standalone = True,
+    deps = [
+        "grpc_common",
+        "grpc_lb_policy_grpclb_secure",
+        "grpc_resolver_dns_ares",
+        "grpc_secure",
+        "grpc_transport_chttp2_client_secure",
+        "grpc_transport_chttp2_server_secure",
     ],
 )
 
@@ -457,7 +450,7 @@
 )
 
 grpc_cc_library(
-    name = "grpc_base",
+    name = "grpc_base_c",
     srcs = [
         "src/core/lib/channel/channel_args.c",
         "src/core/lib/channel/channel_stack.c",
@@ -479,13 +472,13 @@
         "src/core/lib/iomgr/endpoint_pair_windows.c",
         "src/core/lib/iomgr/error.c",
         "src/core/lib/iomgr/ev_epoll1_linux.c",
-        "src/core/lib/iomgr/ev_epollsig_linux.c",
-        "src/core/lib/iomgr/ev_epollex_linux.c",
-        "src/core/lib/iomgr/is_epollexclusive_available.c",
-        "src/core/lib/iomgr/ev_epoll_thread_pool_linux.c",
         "src/core/lib/iomgr/ev_epoll_limited_pollers_linux.c",
+        "src/core/lib/iomgr/ev_epoll_thread_pool_linux.c",
+        "src/core/lib/iomgr/ev_epollex_linux.c",
+        "src/core/lib/iomgr/ev_epollsig_linux.c",
         "src/core/lib/iomgr/ev_poll_posix.c",
         "src/core/lib/iomgr/ev_posix.c",
+        "src/core/lib/iomgr/ev_windows.c",
         "src/core/lib/iomgr/exec_ctx.c",
         "src/core/lib/iomgr/executor.c",
         "src/core/lib/iomgr/iocp_windows.c",
@@ -493,6 +486,7 @@
         "src/core/lib/iomgr/iomgr_posix.c",
         "src/core/lib/iomgr/iomgr_uv.c",
         "src/core/lib/iomgr/iomgr_windows.c",
+        "src/core/lib/iomgr/is_epollexclusive_available.c",
         "src/core/lib/iomgr/load_file.c",
         "src/core/lib/iomgr/lockfree_event.c",
         "src/core/lib/iomgr/network_status_tracker.c",
@@ -528,8 +522,8 @@
         "src/core/lib/iomgr/tcp_windows.c",
         "src/core/lib/iomgr/time_averaged_stats.c",
         "src/core/lib/iomgr/timer_generic.c",
-        "src/core/lib/iomgr/timer_manager.c",
         "src/core/lib/iomgr/timer_heap.c",
+        "src/core/lib/iomgr/timer_manager.c",
         "src/core/lib/iomgr/timer_uv.c",
         "src/core/lib/iomgr/udp_server.c",
         "src/core/lib/iomgr/unix_sockets_posix.c",
@@ -566,7 +560,6 @@
         "src/core/lib/surface/completion_queue.c",
         "src/core/lib/surface/completion_queue_factory.c",
         "src/core/lib/surface/event_string.c",
-        "src/core/lib/surface/lame_client.cc",
         "src/core/lib/surface/metadata_array.c",
         "src/core/lib/surface/server.c",
         "src/core/lib/surface/validate_metadata.c",
@@ -606,12 +599,10 @@
         "src/core/lib/iomgr/error.h",
         "src/core/lib/iomgr/error_internal.h",
         "src/core/lib/iomgr/ev_epoll1_linux.h",
-        "src/core/lib/iomgr/ev_epollsig_linux.h",
-        "src/core/lib/iomgr/ev_epollex_linux.h",
-        "src/core/lib/iomgr/is_epollexclusive_available.h",
-        "src/core/lib/iomgr/sys_epoll_wrapper.h",
-        "src/core/lib/iomgr/ev_epoll_thread_pool_linux.h",
         "src/core/lib/iomgr/ev_epoll_limited_pollers_linux.h",
+        "src/core/lib/iomgr/ev_epoll_thread_pool_linux.h",
+        "src/core/lib/iomgr/ev_epollex_linux.h",
+        "src/core/lib/iomgr/ev_epollsig_linux.h",
         "src/core/lib/iomgr/ev_poll_posix.h",
         "src/core/lib/iomgr/ev_posix.h",
         "src/core/lib/iomgr/exec_ctx.h",
@@ -620,6 +611,7 @@
         "src/core/lib/iomgr/iomgr.h",
         "src/core/lib/iomgr/iomgr_internal.h",
         "src/core/lib/iomgr/iomgr_posix.h",
+        "src/core/lib/iomgr/is_epollexclusive_available.h",
         "src/core/lib/iomgr/load_file.h",
         "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/network_status_tracker.h",
@@ -641,6 +633,7 @@
         "src/core/lib/iomgr/socket_utils.h",
         "src/core/lib/iomgr/socket_utils_posix.h",
         "src/core/lib/iomgr/socket_windows.h",
+        "src/core/lib/iomgr/sys_epoll_wrapper.h",
         "src/core/lib/iomgr/tcp_client.h",
         "src/core/lib/iomgr/tcp_client_posix.h",
         "src/core/lib/iomgr/tcp_posix.h",
@@ -651,8 +644,8 @@
         "src/core/lib/iomgr/time_averaged_stats.h",
         "src/core/lib/iomgr/timer.h",
         "src/core/lib/iomgr/timer_generic.h",
-        "src/core/lib/iomgr/timer_manager.h",
         "src/core/lib/iomgr/timer_heap.h",
+        "src/core/lib/iomgr/timer_manager.h",
         "src/core/lib/iomgr/timer_uv.h",
         "src/core/lib/iomgr/udp_server.h",
         "src/core/lib/iomgr/unix_sockets_posix.h",
@@ -714,6 +707,7 @@
         "include/grpc/slice.h",
         "include/grpc/slice_buffer.h",
         "include/grpc/status.h",
+        "include/grpc/support/workaround_list.h",
     ],
     deps = [
         "gpr_base",
@@ -723,6 +717,38 @@
 )
 
 grpc_cc_library(
+    name = "grpc_base",
+    srcs = [
+        "src/core/lib/surface/lame_client.cc",
+    ],
+    language = "c++",
+    deps = [
+        "grpc_base_c",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_common",
+    deps = [
+        "grpc_base",
+        # standard plugins
+        "census",
+        "grpc_deadline_filter",
+        "grpc_lb_policy_pick_first",
+        "grpc_lb_policy_round_robin",
+        "grpc_load_reporting",
+        "grpc_max_age_filter",
+        "grpc_message_size_filter",
+        "grpc_resolver_dns_native",
+        "grpc_resolver_sockaddr",
+        "grpc_transport_chttp2_client_insecure",
+        "grpc_transport_chttp2_server_insecure",
+        "grpc_workaround_cronet_compression_filter",
+        "grpc_server_backward_compatibility",
+    ]
+)
+
+grpc_cc_library(
     name = "grpc_client_channel",
     srcs = [
         "src/core/ext/filters/client_channel/channel_connectivity.c",
@@ -835,6 +861,21 @@
 )
 
 grpc_cc_library(
+    name = "grpc_workaround_cronet_compression_filter",
+    srcs = [
+        "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c",
+    ],
+    hdrs = [
+        "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+        "grpc_server_backward_compatibility",
+    ],
+)
+
+grpc_cc_library(
     name = "grpc_codegen",
     language = "c",
     public_hdrs = [
@@ -1260,111 +1301,124 @@
     ],
 )
 
-grpc_cc_libraries(
-    srcs = [
-        "src/cpp/client/channel_cc.cc",
-        "src/cpp/client/client_context.cc",
-        "src/cpp/client/create_channel.cc",
-        "src/cpp/client/create_channel_internal.cc",
-        "src/cpp/client/create_channel_posix.cc",
-        "src/cpp/client/credentials_cc.cc",
-        "src/cpp/client/generic_stub.cc",
-        "src/cpp/common/channel_arguments.cc",
-        "src/cpp/common/channel_filter.cc",
-        "src/cpp/common/completion_queue_cc.cc",
-        "src/cpp/common/core_codegen.cc",
-        "src/cpp/common/resource_quota_cc.cc",
-        "src/cpp/common/rpc_method.cc",
-        "src/cpp/common/version_cc.cc",
-        "src/cpp/server/async_generic_service.cc",
-        "src/cpp/server/channel_argument_option.cc",
-        "src/cpp/server/create_default_thread_pool.cc",
-        "src/cpp/server/dynamic_thread_pool.cc",
-        "src/cpp/server/health/default_health_check_service.cc",
-        "src/cpp/server/health/health.pb.c",
-        "src/cpp/server/health/health_check_service.cc",
-        "src/cpp/server/health/health_check_service_server_builder_option.cc",
-        "src/cpp/server/server_builder.cc",
-        "src/cpp/server/server_cc.cc",
-        "src/cpp/server/server_context.cc",
-        "src/cpp/server/server_credentials.cc",
-        "src/cpp/server/server_posix.cc",
-        "src/cpp/thread_manager/thread_manager.cc",
-        "src/cpp/util/byte_buffer_cc.cc",
-        "src/cpp/util/slice_cc.cc",
-        "src/cpp/util/status.cc",
-        "src/cpp/util/string_ref.cc",
-        "src/cpp/util/time_cc.cc",
-    ],
-    hdrs = [
-        "src/cpp/client/create_channel_internal.h",
-        "src/cpp/common/channel_filter.h",
-        "src/cpp/server/dynamic_thread_pool.h",
-        "src/cpp/server/health/default_health_check_service.h",
-        "src/cpp/server/health/health.pb.h",
-        "src/cpp/server/thread_pool_interface.h",
-        "src/cpp/thread_manager/thread_manager.h",
-    ],
-    additional_dep_list = [
-        ["grpc"],
-        ["grpc_unsecure"],
-    ],
+# TODO(ctiller): layer grpc atop grpc_unsecure, layer grpc++ atop grpc++_unsecure
+GRPCXX_SRCS = [
+    "src/cpp/client/channel_cc.cc",
+    "src/cpp/client/client_context.cc",
+    "src/cpp/client/create_channel.cc",
+    "src/cpp/client/create_channel_internal.cc",
+    "src/cpp/client/create_channel_posix.cc",
+    "src/cpp/client/credentials_cc.cc",
+    "src/cpp/client/generic_stub.cc",
+    "src/cpp/common/channel_arguments.cc",
+    "src/cpp/common/channel_filter.cc",
+    "src/cpp/common/completion_queue_cc.cc",
+    "src/cpp/common/core_codegen.cc",
+    "src/cpp/common/resource_quota_cc.cc",
+    "src/cpp/common/rpc_method.cc",
+    "src/cpp/common/version_cc.cc",
+    "src/cpp/server/async_generic_service.cc",
+    "src/cpp/server/channel_argument_option.cc",
+    "src/cpp/server/create_default_thread_pool.cc",
+    "src/cpp/server/dynamic_thread_pool.cc",
+    "src/cpp/server/health/default_health_check_service.cc",
+    "src/cpp/server/health/health.pb.c",
+    "src/cpp/server/health/health_check_service.cc",
+    "src/cpp/server/health/health_check_service_server_builder_option.cc",
+    "src/cpp/server/server_builder.cc",
+    "src/cpp/server/server_cc.cc",
+    "src/cpp/server/server_context.cc",
+    "src/cpp/server/server_credentials.cc",
+    "src/cpp/server/server_posix.cc",
+    "src/cpp/thread_manager/thread_manager.cc",
+    "src/cpp/util/byte_buffer_cc.cc",
+    "src/cpp/util/slice_cc.cc",
+    "src/cpp/util/status.cc",
+    "src/cpp/util/string_ref.cc",
+    "src/cpp/util/time_cc.cc",
+]
+
+GRPCXX_HDRS = [
+    "src/cpp/client/create_channel_internal.h",
+    "src/cpp/common/channel_filter.h",
+    "src/cpp/server/dynamic_thread_pool.h",
+    "src/cpp/server/health/default_health_check_service.h",
+    "src/cpp/server/health/health.pb.h",
+    "src/cpp/server/thread_pool_interface.h",
+    "src/cpp/thread_manager/thread_manager.h",
+]
+
+GRPCXX_PUBLIC_HDRS = [
+    "include/grpc++/alarm.h",
+    "include/grpc++/channel.h",
+    "include/grpc++/client_context.h",
+    "include/grpc++/completion_queue.h",
+    "include/grpc++/create_channel.h",
+    "include/grpc++/create_channel_posix.h",
+    "include/grpc++/ext/health_check_service_server_builder_option.h",
+    "include/grpc++/generic/async_generic_service.h",
+    "include/grpc++/generic/generic_stub.h",
+    "include/grpc++/grpc++.h",
+    "include/grpc++/health_check_service_interface.h",
+    "include/grpc++/impl/call.h",
+    "include/grpc++/impl/channel_argument_option.h",
+    "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/codegen/core_codegen.h",
+    "include/grpc++/impl/grpc_library.h",
+    "include/grpc++/impl/method_handler_impl.h",
+    "include/grpc++/impl/rpc_method.h",
+    "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/serialization_traits.h",
+    "include/grpc++/impl/server_builder_option.h",
+    "include/grpc++/impl/server_builder_plugin.h",
+    "include/grpc++/impl/server_initializer.h",
+    "include/grpc++/impl/service_type.h",
+    "include/grpc++/impl/sync_cxx11.h",
+    "include/grpc++/impl/sync_no_cxx11.h",
+    "include/grpc++/resource_quota.h",
+    "include/grpc++/security/auth_context.h",
+    "include/grpc++/security/auth_metadata_processor.h",
+    "include/grpc++/security/credentials.h",
+    "include/grpc++/security/server_credentials.h",
+    "include/grpc++/server.h",
+    "include/grpc++/server_builder.h",
+    "include/grpc++/server_context.h",
+    "include/grpc++/server_posix.h",
+    "include/grpc++/support/async_stream.h",
+    "include/grpc++/support/async_unary_call.h",
+    "include/grpc++/support/byte_buffer.h",
+    "include/grpc++/support/channel_arguments.h",
+    "include/grpc++/support/config.h",
+    "include/grpc++/support/slice.h",
+    "include/grpc++/support/status.h",
+    "include/grpc++/support/status_code_enum.h",
+    "include/grpc++/support/string_ref.h",
+    "include/grpc++/support/stub_options.h",
+    "include/grpc++/support/sync_stream.h",
+    "include/grpc++/support/time.h",
+]
+
+grpc_cc_library(
+    name = "grpc++_base",
+    hdrs = GRPCXX_HDRS,
+    srcs = GRPCXX_SRCS,
+    public_hdrs = GRPCXX_PUBLIC_HDRS,
     language = "c++",
-    name_list = [
-        "grpc++_base",
-        "grpc++_base_unsecure",
-    ],
-    public_hdrs = [
-        "include/grpc++/alarm.h",
-        "include/grpc++/channel.h",
-        "include/grpc++/client_context.h",
-        "include/grpc++/completion_queue.h",
-        "include/grpc++/create_channel.h",
-        "include/grpc++/create_channel_posix.h",
-        "include/grpc++/ext/health_check_service_server_builder_option.h",
-        "include/grpc++/generic/async_generic_service.h",
-        "include/grpc++/generic/generic_stub.h",
-        "include/grpc++/grpc++.h",
-        "include/grpc++/health_check_service_interface.h",
-        "include/grpc++/impl/call.h",
-        "include/grpc++/impl/channel_argument_option.h",
-        "include/grpc++/impl/client_unary_call.h",
-        "include/grpc++/impl/codegen/core_codegen.h",
-        "include/grpc++/impl/grpc_library.h",
-        "include/grpc++/impl/method_handler_impl.h",
-        "include/grpc++/impl/rpc_method.h",
-        "include/grpc++/impl/rpc_service_method.h",
-        "include/grpc++/impl/serialization_traits.h",
-        "include/grpc++/impl/server_builder_option.h",
-        "include/grpc++/impl/server_builder_plugin.h",
-        "include/grpc++/impl/server_initializer.h",
-        "include/grpc++/impl/service_type.h",
-        "include/grpc++/impl/sync_cxx11.h",
-        "include/grpc++/impl/sync_no_cxx11.h",
-        "include/grpc++/resource_quota.h",
-        "include/grpc++/security/auth_context.h",
-        "include/grpc++/security/auth_metadata_processor.h",
-        "include/grpc++/security/credentials.h",
-        "include/grpc++/security/server_credentials.h",
-        "include/grpc++/server.h",
-        "include/grpc++/server_builder.h",
-        "include/grpc++/server_context.h",
-        "include/grpc++/server_posix.h",
-        "include/grpc++/support/async_stream.h",
-        "include/grpc++/support/async_unary_call.h",
-        "include/grpc++/support/byte_buffer.h",
-        "include/grpc++/support/channel_arguments.h",
-        "include/grpc++/support/config.h",
-        "include/grpc++/support/slice.h",
-        "include/grpc++/support/status.h",
-        "include/grpc++/support/status_code_enum.h",
-        "include/grpc++/support/string_ref.h",
-        "include/grpc++/support/stub_options.h",
-        "include/grpc++/support/sync_stream.h",
-        "include/grpc++/support/time.h",
-    ],
     deps = [
         "grpc++_codegen_base",
+        "grpc",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc++_base_unsecure",
+    hdrs = GRPCXX_HDRS,
+    srcs = GRPCXX_SRCS,
+    public_hdrs = GRPCXX_PUBLIC_HDRS,
+    language = "c++",
+    deps = [
+        "grpc++_codegen_base",
+        "grpc_unsecure",
     ],
 )
 
@@ -1459,3 +1513,31 @@
         "//src/proto/grpc/reflection/v1alpha:reflection_proto",
     ],
 )
+
+grpc_cc_library(
+    name = "grpc++_test",
+    public_hdrs = [
+        "include/grpc++/test/mock_stream.h",
+        "include/grpc++/test/server_context_test_spouse.h",
+    ],
+    deps = [
+        ":grpc++",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_server_backward_compatibility",
+    srcs = [
+        "src/core/ext/filters/workarounds/workaround_utils.c",
+    ],
+    hdrs = [
+        "src/core/ext/filters/workarounds/workaround_utils.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+
+grpc_generate_one_off_targets()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93f8393..d10c040 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -563,6 +563,7 @@
 add_dependencies(buildtests_c h2_full+pipe_test)
 endif()
 add_dependencies(buildtests_c h2_full+trace_test)
+add_dependencies(buildtests_c h2_full+workarounds_test)
 add_dependencies(buildtests_c h2_http_proxy_test)
 add_dependencies(buildtests_c h2_load_reporting_test)
 add_dependencies(buildtests_c h2_oauth2_test)
@@ -586,6 +587,7 @@
 add_dependencies(buildtests_c h2_full+pipe_nosec_test)
 endif()
 add_dependencies(buildtests_c h2_full+trace_nosec_test)
+add_dependencies(buildtests_c h2_full+workarounds_nosec_test)
 add_dependencies(buildtests_c h2_http_proxy_nosec_test)
 add_dependencies(buildtests_c h2_load_reporting_nosec_test)
 add_dependencies(buildtests_c h2_proxy_nosec_test)
@@ -945,6 +947,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -1162,6 +1165,8 @@
   src/core/ext/census/tracing.c
   src/core/ext/filters/max_age/max_age_filter.c
   src/core/ext/filters/message_size/message_size_filter.c
+  src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
+  src/core/ext/filters/workarounds/workaround_utils.c
   src/core/plugin_registry/grpc_plugin_registry.c
 )
 
@@ -1212,6 +1217,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
@@ -1279,6 +1285,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -1509,6 +1516,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
@@ -1596,6 +1604,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -1743,6 +1752,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
@@ -1858,6 +1868,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -2045,6 +2056,8 @@
   src/core/ext/census/tracing.c
   src/core/ext/filters/max_age/max_age_filter.c
   src/core/ext/filters/message_size/message_size_filter.c
+  src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
+  src/core/ext/filters/workarounds/workaround_utils.c
   src/core/plugin_registry/grpc_unsecure_plugin_registry.c
 )
 
@@ -2092,6 +2105,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc/impl/codegen/byte_buffer_reader.h
   include/grpc/impl/codegen/compression_types.h
   include/grpc/impl/codegen/connectivity_state.h
@@ -2285,6 +2299,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -2532,6 +2547,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc++/impl/codegen/proto_utils.h
   include/grpc++/impl/codegen/config_protobuf.h
 )
@@ -2616,6 +2632,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -2930,6 +2947,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
   include/grpc/census.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
@@ -3391,6 +3409,7 @@
   src/core/lib/iomgr/ev_epollsig_linux.c
   src/core/lib/iomgr/ev_poll_posix.c
   src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/ev_windows.c
   src/core/lib/iomgr/exec_ctx.c
   src/core/lib/iomgr/executor.c
   src/core/lib/iomgr/iocp_windows.c
@@ -3637,6 +3656,7 @@
   include/grpc/slice.h
   include/grpc/slice_buffer.h
   include/grpc/status.h
+  include/grpc/support/workaround_list.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -4578,6 +4598,7 @@
   test/core/end2end/tests/simple_request.c
   test/core/end2end/tests/streaming_error_response.c
   test/core/end2end/tests/trailing_metadata.c
+  test/core/end2end/tests/workaround_cronet_compression.c
   test/core/end2end/tests/write_buffering.c
   test/core/end2end/tests/write_buffering_at_end.c
 )
@@ -4675,6 +4696,7 @@
   test/core/end2end/tests/simple_request.c
   test/core/end2end/tests/streaming_error_response.c
   test/core/end2end/tests/trailing_metadata.c
+  test/core/end2end/tests/workaround_cronet_compression.c
   test/core/end2end/tests/write_buffering.c
   test/core/end2end/tests/write_buffering_at_end.c
 )
@@ -13129,6 +13151,38 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(h2_full+workarounds_test
+  test/core/end2end/fixtures/h2_full+workarounds.c
+)
+
+
+target_include_directories(h2_full+workarounds_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(h2_full+workarounds_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  end2end_tests
+  grpc_test_util
+  grpc
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(h2_http_proxy_test
   test/core/end2end/fixtures/h2_http_proxy.c
 )
@@ -13679,6 +13733,38 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(h2_full+workarounds_nosec_test
+  test/core/end2end/fixtures/h2_full+workarounds.c
+)
+
+
+target_include_directories(h2_full+workarounds_nosec_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(h2_full+workarounds_nosec_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  end2end_nosec_tests
+  grpc_test_util_unsecure
+  grpc_unsecure
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(h2_http_proxy_nosec_test
   test/core/end2end/fixtures/h2_http_proxy.c
 )
diff --git a/Makefile b/Makefile
index 5a5617e..e6dd66e 100644
--- a/Makefile
+++ b/Makefile
@@ -1249,6 +1249,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_full+workarounds_test: $(BINDIR)/$(CONFIG)/h2_full+workarounds_test
 h2_http_proxy_test: $(BINDIR)/$(CONFIG)/h2_http_proxy_test
 h2_load_reporting_test: $(BINDIR)/$(CONFIG)/h2_load_reporting_test
 h2_oauth2_test: $(BINDIR)/$(CONFIG)/h2_oauth2_test
@@ -1266,6 +1267,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_full+workarounds_nosec_test: $(BINDIR)/$(CONFIG)/h2_full+workarounds_nosec_test
 h2_http_proxy_nosec_test: $(BINDIR)/$(CONFIG)/h2_http_proxy_nosec_test
 h2_load_reporting_nosec_test: $(BINDIR)/$(CONFIG)/h2_load_reporting_nosec_test
 h2_proxy_nosec_test: $(BINDIR)/$(CONFIG)/h2_proxy_nosec_test
@@ -1494,6 +1496,7 @@
   $(BINDIR)/$(CONFIG)/h2_full_test \
   $(BINDIR)/$(CONFIG)/h2_full+pipe_test \
   $(BINDIR)/$(CONFIG)/h2_full+trace_test \
+  $(BINDIR)/$(CONFIG)/h2_full+workarounds_test \
   $(BINDIR)/$(CONFIG)/h2_http_proxy_test \
   $(BINDIR)/$(CONFIG)/h2_load_reporting_test \
   $(BINDIR)/$(CONFIG)/h2_oauth2_test \
@@ -1511,6 +1514,7 @@
   $(BINDIR)/$(CONFIG)/h2_full_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_full+pipe_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_full+trace_nosec_test \
+  $(BINDIR)/$(CONFIG)/h2_full+workarounds_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_http_proxy_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_load_reporting_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_proxy_nosec_test \
@@ -2920,6 +2924,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -3137,6 +3142,8 @@
     src/core/ext/census/tracing.c \
     src/core/ext/filters/max_age/max_age_filter.c \
     src/core/ext/filters/message_size/message_size_filter.c \
+    src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c \
+    src/core/ext/filters/workarounds/workaround_utils.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -3150,6 +3157,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
@@ -3252,6 +3260,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -3447,6 +3456,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
@@ -3568,6 +3578,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -3680,6 +3691,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
@@ -3802,6 +3814,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -3989,6 +4002,8 @@
     src/core/ext/census/tracing.c \
     src/core/ext/filters/max_age/max_age_filter.c \
     src/core/ext/filters/message_size/message_size_filter.c \
+    src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c \
+    src/core/ext/filters/workarounds/workaround_utils.c \
     src/core/plugin_registry/grpc_unsecure_plugin_registry.c \
 
 PUBLIC_HEADERS_C += \
@@ -4002,6 +4017,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
     include/grpc/impl/codegen/compression_types.h \
     include/grpc/impl/codegen/connectivity_state.h \
@@ -4206,6 +4222,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -4415,6 +4432,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc++/impl/codegen/proto_utils.h \
     include/grpc++/impl/codegen/config_protobuf.h \
 
@@ -4545,6 +4563,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -4821,6 +4840,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
     include/grpc/census.h \
 
 LIBGRPC++_CRONET_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_CRONET_SRC))))
@@ -5310,6 +5330,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -5519,6 +5540,7 @@
     include/grpc/slice.h \
     include/grpc/slice_buffer.h \
     include/grpc/status.h \
+    include/grpc/support/workaround_list.h \
 
 LIBGRPC++_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_UNSECURE_SRC))))
 
@@ -8466,6 +8488,7 @@
     test/core/end2end/tests/simple_request.c \
     test/core/end2end/tests/streaming_error_response.c \
     test/core/end2end/tests/trailing_metadata.c \
+    test/core/end2end/tests/workaround_cronet_compression.c \
     test/core/end2end/tests/write_buffering.c \
     test/core/end2end/tests/write_buffering_at_end.c \
 
@@ -8558,6 +8581,7 @@
     test/core/end2end/tests/simple_request.c \
     test/core/end2end/tests/streaming_error_response.c \
     test/core/end2end/tests/trailing_metadata.c \
+    test/core/end2end/tests/workaround_cronet_compression.c \
     test/core/end2end/tests/write_buffering.c \
     test/core/end2end/tests/write_buffering_at_end.c \
 
@@ -18603,6 +18627,38 @@
 endif
 
 
+H2_FULL+WORKAROUNDS_TEST_SRC = \
+    test/core/end2end/fixtures/h2_full+workarounds.c \
+
+H2_FULL+WORKAROUNDS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FULL+WORKAROUNDS_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/h2_full+workarounds_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/h2_full+workarounds_test: $(H2_FULL+WORKAROUNDS_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_FULL+WORKAROUNDS_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_full+workarounds_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+workarounds.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_full+workarounds_test: $(H2_FULL+WORKAROUNDS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(H2_FULL+WORKAROUNDS_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 H2_HTTP_PROXY_TEST_SRC = \
     test/core/end2end/fixtures/h2_http_proxy.c \
 
@@ -19075,6 +19131,26 @@
 endif
 
 
+H2_FULL+WORKAROUNDS_NOSEC_TEST_SRC = \
+    test/core/end2end/fixtures/h2_full+workarounds.c \
+
+H2_FULL+WORKAROUNDS_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(H2_FULL+WORKAROUNDS_NOSEC_TEST_SRC))))
+
+
+$(BINDIR)/$(CONFIG)/h2_full+workarounds_nosec_test: $(H2_FULL+WORKAROUNDS_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_FULL+WORKAROUNDS_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_full+workarounds_nosec_test
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/h2_full+workarounds.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_full+workarounds_nosec_test: $(H2_FULL+WORKAROUNDS_NOSEC_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(H2_FULL+WORKAROUNDS_NOSEC_TEST_OBJS:.o=.dep)
+endif
+
+
 H2_HTTP_PROXY_NOSEC_TEST_SRC = \
     test/core/end2end/fixtures/h2_http_proxy.c \
 
diff --git a/WORKSPACE b/WORKSPACE
index a78a889..82ea99f 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -5,7 +5,7 @@
 
 bind(
     name = "libssl",
-    actual = "@submodule_boringssl//:ssl",
+    actual = "@boringssl//:ssl",
 )
 
 bind(
@@ -49,7 +49,7 @@
 )
 
 local_repository(
-    name = "submodule_boringssl",
+    name = "boringssl",
     path = "third_party/boringssl-with-bazel",
 )
 
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index a104fa0..0f66edb 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -32,8 +32,15 @@
 # the BUILD file for gRPC. It contains the mapping for the template system we
 # use to generate other platform's build system files.
 #
+# Please consider that there should be a high bar for additions and changes to
+# this file.
+# Each rule listed must be re-written for Google's internal build system, and
+# each change must be ported from one to the other.
+#
 
-def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language = "C++"):
+def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [],
+                    external_deps = [], deps = [], standalone = False,
+                    language = "C++", testonly = False, visibility = None):
   copts = []
   if language.upper() == "C":
     copts = ["-std=c99"]
@@ -43,28 +50,14 @@
     hdrs = hdrs + public_hdrs,
     deps = deps + ["//external:" + dep for dep in external_deps],
     copts = copts,
+    visibility = visibility,
+    testonly = testonly,
     linkopts = ["-pthread"],
     includes = [
         "include"
     ]
   )
 
-def grpc_cc_libraries(name_list, additional_src_list = [], additional_dep_list = [], srcs = [], public_hdrs = [], hdrs = [], external_deps = [], deps = [], standalone = False, language="C++"):
-  names = len(name_list)
-  asl = additional_src_list + [[]]*(names - len(additional_src_list))
-  adl = additional_dep_list + [[]]*(names - len(additional_dep_list))
-  for i in range(names):
-    grpc_cc_library(
-      name = name_list[i],
-      srcs = srcs + asl[i],
-      hdrs = hdrs,
-      public_hdrs = public_hdrs,
-      deps = deps + adl[i],
-      external_deps = external_deps,
-      standalone = standalone,
-      language = language
-    )
-
 def grpc_proto_plugin(name, srcs = [], deps = []):
   native.cc_binary(
     name = name,
@@ -86,3 +79,42 @@
     generate_mock = generate_mock,
   )
 
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++"):
+  copts = []
+  if language.upper() == "C":
+    copts = ["-std=c99"]
+  native.cc_test(
+    name = name,
+    srcs = srcs,
+    args = args,
+    data = data,
+    deps = deps + ["//external:" + dep for dep in external_deps],
+    copts = copts,
+    linkopts = ["-pthread"],
+  )
+
+def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False):
+  copts = []
+  if language.upper() == "C":
+    copts = ["-std=c99"]
+  native.cc_binary(
+    name = name,
+    srcs = srcs,
+    args = args,
+    data = data,
+    testonly = testonly,
+    linkshared = linkshared,
+    deps = deps + ["//external:" + dep for dep in external_deps],
+    copts = copts,
+    linkopts = ["-pthread"],
+  )
+
+def grpc_generate_one_off_targets():
+    pass
+
+def grpc_sh_test(name, srcs, args = [], data = []):
+    native.sh_test(
+        name = name,
+        srcs = srcs,
+        args = args,
+        data = data)
diff --git a/binding.gyp b/binding.gyp
index c47cd00..8aafdaa 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -680,6 +680,7 @@
         'src/core/lib/iomgr/ev_epollsig_linux.c',
         'src/core/lib/iomgr/ev_poll_posix.c',
         'src/core/lib/iomgr/ev_posix.c',
+        'src/core/lib/iomgr/ev_windows.c',
         'src/core/lib/iomgr/exec_ctx.c',
         'src/core/lib/iomgr/executor.c',
         'src/core/lib/iomgr/iocp_windows.c',
@@ -897,6 +898,8 @@
         'src/core/ext/census/tracing.c',
         'src/core/ext/filters/max_age/max_age_filter.c',
         'src/core/ext/filters/message_size/message_size_filter.c',
+        'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c',
+        'src/core/ext/filters/workarounds/workaround_utils.c',
         'src/core/plugin_registry/grpc_plugin_registry.c',
       ],
       "conditions": [
diff --git a/build.yaml b/build.yaml
index a883229..2c54055 100644
--- a/build.yaml
+++ b/build.yaml
@@ -176,6 +176,7 @@
   - include/grpc/slice.h
   - include/grpc/slice_buffer.h
   - include/grpc/status.h
+  - include/grpc/support/workaround_list.h
   headers:
   - src/core/lib/channel/channel_args.h
   - src/core/lib/channel/channel_stack.h
@@ -316,6 +317,7 @@
   - src/core/lib/iomgr/ev_epollsig_linux.c
   - src/core/lib/iomgr/ev_poll_posix.c
   - src/core/lib/iomgr/ev_posix.c
+  - src/core/lib/iomgr/ev_windows.c
   - src/core/lib/iomgr/exec_ctx.c
   - src/core/lib/iomgr/executor.c
   - src/core/lib/iomgr/iocp_windows.c
@@ -658,6 +660,13 @@
   - grpc_base
   - grpc_transport_chttp2_alpn
   - tsi
+- name: grpc_server_backward_compatibility
+  headers:
+  - src/core/ext/filters/workarounds/workaround_utils.h
+  src:
+  - src/core/ext/filters/workarounds/workaround_utils.c
+  uses:
+  - grpc_base
 - name: grpc_test_util_base
   build: test
   headers:
@@ -824,6 +833,15 @@
   - grpc_base
   - grpc_transport_chttp2
   - grpc_http_filters
+- name: grpc_workaround_cronet_compression_filter
+  headers:
+  - src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
+  src:
+  - src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
+  plugin: grpc_workaround_cronet_compression_filter
+  uses:
+  - grpc_base
+  - grpc_server_backward_compatibility
 - name: nanopb
   headers:
   - third_party/nanopb/pb.h
@@ -1053,6 +1071,8 @@
   - grpc_max_age_filter
   - grpc_message_size_filter
   - grpc_deadline_filter
+  - grpc_workaround_cronet_compression_filter
+  - grpc_server_backward_compatibility
   generate_plugin_registry: true
   secure: true
   vs_packages:
@@ -1152,6 +1172,8 @@
   - grpc_max_age_filter
   - grpc_message_size_filter
   - grpc_deadline_filter
+  - grpc_workaround_cronet_compression_filter
+  - grpc_server_backward_compatibility
   generate_plugin_registry: true
   secure: false
   vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}'
@@ -3343,7 +3365,7 @@
   - gpr_test_util
   - gpr
   args:
-  - --benchmark_min_time=0
+  - --benchmark_min_time=4
   defaults: benchmark
   platforms:
   - mac
@@ -4581,6 +4603,7 @@
   - src/node/src/client.js
   - src/node/src/common.js
   - src/node/src/credentials.js
+  - src/node/src/constants.js
   - src/node/src/grpc_extension.js
   - src/node/src/metadata.js
   - src/node/src/server.js
diff --git a/composer.json b/composer.json
index 284b57a..2cf3f17 100644
--- a/composer.json
+++ b/composer.json
@@ -6,12 +6,15 @@
   "homepage": "http://grpc.io",
   "license": "BSD-3-Clause",
   "require": {
-    "php": ">=5.5.0",
-    "google/protobuf": "^v3.3.0"
+    "php": ">=5.5.0"
   },
   "require-dev": {
     "google/auth": "v0.9"
   },
+  "suggest": {
+    "ext-protobuf": "For better performance, install the protobuf C extension.",
+    "google/protobuf": "To get started using grpc quickly, install the native protobuf library."
+  },
   "autoload": {
     "psr-4": {
       "Grpc\\": "src/php/lib/Grpc/"
diff --git a/config.m4 b/config.m4
index 99baebf..cc050ed 100644
--- a/config.m4
+++ b/config.m4
@@ -114,6 +114,7 @@
     src/core/lib/iomgr/ev_epollsig_linux.c \
     src/core/lib/iomgr/ev_poll_posix.c \
     src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/ev_windows.c \
     src/core/lib/iomgr/exec_ctx.c \
     src/core/lib/iomgr/executor.c \
     src/core/lib/iomgr/iocp_windows.c \
@@ -331,6 +332,8 @@
     src/core/ext/census/tracing.c \
     src/core/ext/filters/max_age/max_age_filter.c \
     src/core/ext/filters/message_size/message_size_filter.c \
+    src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c \
+    src/core/ext/filters/workarounds/workaround_utils.c \
     src/core/plugin_registry/grpc_plugin_registry.c \
     src/boringssl/err_data.c \
     third_party/boringssl/crypto/aes/aes.c \
@@ -711,6 +714,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/load_reporting)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/max_age)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/message_size)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/workarounds)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/alpn)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/client/insecure)
diff --git a/doc/unit_testing.md b/doc/unit_testing.md
new file mode 100644
index 0000000..0aa9be9
--- /dev/null
+++ b/doc/unit_testing.md
@@ -0,0 +1,175 @@
+# How to write unit tests for gRPC C client.
+
+tl;dr: [Example code](https://github.com/grpc/grpc/blob/master/test/cpp/end2end/mock_test.cc).
+
+To unit-test client-side logic via the synchronous API, gRPC provides a mocked Stub based on googletest(googlemock) that can be programmed upon and easily incorporated in the test code.
+
+For instance, consider an EchoService like this:
+
+
+```proto
+service EchoTestService {
+        rpc Echo(EchoRequest) returns (EchoResponse);
+        rpc BidiStream(stream EchoRequest) returns (stream EchoResponse);
+}
+```
+
+The code generated would look something like this:
+
+```c
+class EchoTestService final {
+  public:
+  class StubInterface {
+    virtual ::grpc::Status Echo(::grpc::ClientContext* context, const ::grpc::testing::EchoRequest& request, ::grpc::testing::EchoResponse* response) = 0;
+  …
+    std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::testing::EchoRequest, ::grpc::testing::EchoResponse>> BidiStream(::grpc::ClientContext* context) {
+      return std::unique_ptr< ::grpc::ClientReaderWriterInterface< ::grpc::testing::EchoRequest, ::grpc::testing::EchoResponse>>(BidiStreamRaw(context));
+    }
+  …
+    private:
+    virtual ::grpc::ClientReaderWriterInterface< ::grpc::testing::EchoRequest, ::grpc::testing::EchoResponse>* BidiStreamRaw(::grpc::ClientContext* context) = 0;
+  …
+  } // End StubInterface
+…
+} // End EchoTestService
+```
+
+
+If we mock the StubInterface and set expectations on the pure-virtual methods we can test client-side logic without having to make any rpcs.
+
+A mock for this StubInterface will look like this:
+
+
+```c
+class MockEchoTestServiceStub : public EchoTestService::StubInterface {
+ public:
+  MOCK_METHOD3(Echo, ::grpc::Status(::grpc::ClientContext* context, const ::grpc::testing::EchoRequest& request, ::grpc::testing::EchoResponse* response));
+  MOCK_METHOD1(BidiStreamRaw, ::grpc::ClientReaderWriterInterface< ::grpc::testing::EchoRequest, ::grpc::testing::EchoResponse>*(::grpc::ClientContext* context));
+};
+```
+
+
+**Generating mock code:**
+
+Such a mock can be auto-generated by:
+
+
+
+1.  Setting flag(generate_mock_code=true) on grpc plugin for protoc, or
+1.  Setting an attribute(generate_mock) in your bazel rule.
+
+Protoc plugin flag:
+
+```sh
+protoc -I . --grpc_out=generate_mock_code=true:. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` echo.proto
+```
+
+Bazel rule:
+
+```py
+grpc_proto_library(
+  name = "echo_proto",
+  srcs = ["echo.proto"],
+  generate_mock = True, 
+)
+```
+
+
+By adding such a flag now a header file `echo_mock.grpc.pb.h` containing the mocked stub will also be generated. 
+
+This header file can then be included in test files along with a gmock dependency.
+
+**Writing tests with mocked Stub.**
+
+Consider the following client a user might have:
+
+```c
+class FakeClient {
+ public:
+  explicit FakeClient(EchoTestService::StubInterface* stub) : stub_(stub) {}
+
+  void DoEcho() {
+    ClientContext context;
+    EchoRequest request;
+    EchoResponse response;
+    request.set_message("hello world");
+    Status s = stub_->Echo(&context, request, &response);
+    EXPECT_EQ(request.message(), response.message());
+    EXPECT_TRUE(s.ok());
+  }
+
+  void DoBidiStream() {
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+    grpc::string msg("hello");
+
+    std::unique_ptr<ClientReaderWriterInterface<EchoRequest, EchoResponse>>
+        stream = stub_->BidiStream(&context);
+
+    request.set_message(msg  "0");
+    EXPECT_TRUE(stream->Write(request));
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message());
+
+    request.set_message(msg  "1");
+    EXPECT_TRUE(stream->Write(request));
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message());
+
+    request.set_message(msg  "2");
+    EXPECT_TRUE(stream->Write(request));
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message());
+
+    stream->WritesDone();
+    EXPECT_FALSE(stream->Read(&response));
+
+    Status s = stream->Finish();
+    EXPECT_TRUE(s.ok());
+  }
+
+  void ResetStub(EchoTestService::StubInterface* stub) { stub_ = stub; }
+
+ private:
+  EchoTestService::StubInterface* stub_;
+};
+```
+
+A test could initialize this FakeClient with a mocked stub having set expectations on it:
+
+Unary RPC:
+
+```c
+MockEchoTestServiceStub stub;
+EchoResponse resp;
+resp.set_message("hello world");
+Expect_CALL(stub, Echo(_,_,_)).Times(Atleast(1)).WillOnce(DoAll(SetArgPointee<2>(resp), Return(Status::OK)));
+FakeClient client(stub);
+client.DoEcho();
+```
+
+Streaming RPC:
+
+```c
+ACTION_P(copy, msg) {
+  arg0->set_message(msg->message());
+}
+
+
+auto rw = new MockClientReaderWriter<EchoRequest, EchoResponse>();
+EchoRequest msg;
+EXPECT_CALL(*rw, Write(_, _)).Times(3).WillRepeatedly(DoAll(SaveArg<0>(&msg), Return(true)));
+EXPECT_CALL(*rw, Read(_)).
+      WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true))).
+      WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true))).
+      WillOnce(DoAll(WithArg<0>(copy(&msg)), Return(true))).
+      WillOnce(Return(false));
+
+MockEchoTestServiceStub  stub;
+EXPECT_CALL(stub, BidiStreamRaw(_)).Times(AtLeast(1)).WillOnce(Return(rw));
+
+FakeClient client(stub);
+client.DoBidiStream();
+```
+
diff --git a/examples/BUILD b/examples/BUILD
index 382713e..bd2d3c3 100644
--- a/examples/BUILD
+++ b/examples/BUILD
@@ -54,13 +54,13 @@
 cc_binary(
     name = "greeter_client",
     srcs = ["cpp/helloworld/greeter_client.cc"],
-    deps = ["helloworld"],
     defines = ["BAZEL_BUILD"],
+    deps = [":helloworld"],
 )
 
 cc_binary(
     name = "greeter_server",
     srcs = ["cpp/helloworld/greeter_server.cc"],
-    deps = ["helloworld"],
     defines = ["BAZEL_BUILD"],
+    deps = [":helloworld"],
 )
diff --git a/examples/php/composer.json b/examples/php/composer.json
index f4b177c..9d900eb 100644
--- a/examples/php/composer.json
+++ b/examples/php/composer.json
@@ -2,7 +2,8 @@
   "name": "grpc/grpc-demo",
   "description": "gRPC example for PHP",
   "require": {
-    "grpc/grpc": "^v1.1.0"
+    "grpc/grpc": "^v1.3.0",
+    "google/protobuf": "^v3.3.0"
   },
   "autoload": {
     "psr-4": {
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index a6c083d..1176a15 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -166,6 +166,7 @@
                       'include/grpc/slice.h',
                       'include/grpc/slice_buffer.h',
                       'include/grpc/status.h',
+                      'include/grpc/support/workaround_list.h',
                       'include/grpc/impl/codegen/byte_buffer_reader.h',
                       'include/grpc/impl/codegen/compression_types.h',
                       'include/grpc/impl/codegen/connectivity_state.h',
@@ -473,6 +474,8 @@
                       'src/core/ext/census/tracing.h',
                       'src/core/ext/filters/max_age/max_age_filter.h',
                       'src/core/ext/filters/message_size/message_size_filter.h',
+                      'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
+                      'src/core/ext/filters/workarounds/workaround_utils.h',
                       'src/core/lib/surface/init.c',
                       'src/core/lib/channel/channel_args.c',
                       'src/core/lib/channel/channel_stack.c',
@@ -500,6 +503,7 @@
                       'src/core/lib/iomgr/ev_epollsig_linux.c',
                       'src/core/lib/iomgr/ev_poll_posix.c',
                       'src/core/lib/iomgr/ev_posix.c',
+                      'src/core/lib/iomgr/ev_windows.c',
                       'src/core/lib/iomgr/exec_ctx.c',
                       'src/core/lib/iomgr/executor.c',
                       'src/core/lib/iomgr/iocp_windows.c',
@@ -717,6 +721,8 @@
                       'src/core/ext/census/tracing.c',
                       'src/core/ext/filters/max_age/max_age_filter.c',
                       'src/core/ext/filters/message_size/message_size_filter.c',
+                      'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c',
+                      'src/core/ext/filters/workarounds/workaround_utils.c',
                       'src/core/plugin_registry/grpc_plugin_registry.c'
 
     ss.private_header_files = 'src/core/lib/profiling/timers.h',
@@ -950,7 +956,9 @@
                               'src/core/ext/census/trace_string.h',
                               'src/core/ext/census/tracing.h',
                               'src/core/ext/filters/max_age/max_age_filter.h',
-                              'src/core/ext/filters/message_size/message_size_filter.h'
+                              'src/core/ext/filters/message_size/message_size_filter.h',
+                              'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h',
+                              'src/core/ext/filters/workarounds/workaround_utils.h'
   end
 
   s.subspec 'Cronet-Interface' do |ss|
diff --git a/grpc.gemspec b/grpc.gemspec
index 7fe4fe2..32c1164 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -154,6 +154,7 @@
   s.files += %w( include/grpc/slice.h )
   s.files += %w( include/grpc/slice_buffer.h )
   s.files += %w( include/grpc/status.h )
+  s.files += %w( include/grpc/support/workaround_list.h )
   s.files += %w( include/grpc/impl/codegen/byte_buffer_reader.h )
   s.files += %w( include/grpc/impl/codegen/compression_types.h )
   s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
@@ -389,6 +390,8 @@
   s.files += %w( src/core/ext/census/tracing.h )
   s.files += %w( src/core/ext/filters/max_age/max_age_filter.h )
   s.files += %w( src/core/ext/filters/message_size/message_size_filter.h )
+  s.files += %w( src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h )
+  s.files += %w( src/core/ext/filters/workarounds/workaround_utils.h )
   s.files += %w( src/core/lib/surface/init.c )
   s.files += %w( src/core/lib/channel/channel_args.c )
   s.files += %w( src/core/lib/channel/channel_stack.c )
@@ -416,6 +419,7 @@
   s.files += %w( src/core/lib/iomgr/ev_epollsig_linux.c )
   s.files += %w( src/core/lib/iomgr/ev_poll_posix.c )
   s.files += %w( src/core/lib/iomgr/ev_posix.c )
+  s.files += %w( src/core/lib/iomgr/ev_windows.c )
   s.files += %w( src/core/lib/iomgr/exec_ctx.c )
   s.files += %w( src/core/lib/iomgr/executor.c )
   s.files += %w( src/core/lib/iomgr/iocp_windows.c )
@@ -633,6 +637,8 @@
   s.files += %w( src/core/ext/census/tracing.c )
   s.files += %w( src/core/ext/filters/max_age/max_age_filter.c )
   s.files += %w( src/core/ext/filters/message_size/message_size_filter.c )
+  s.files += %w( src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c )
+  s.files += %w( src/core/ext/filters/workarounds/workaround_utils.c )
   s.files += %w( src/core/plugin_registry/grpc_plugin_registry.c )
   s.files += %w( third_party/boringssl/crypto/aes/internal.h )
   s.files += %w( third_party/boringssl/crypto/asn1/asn1_locl.h )
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index a56f81d..5a85776 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -195,7 +195,7 @@
 
   struct SyncServerSettings {
     SyncServerSettings()
-        : num_cqs(gpr_cpu_num_cores()),
+        : num_cqs(GPR_MAX(1, gpr_cpu_num_cores())),
           min_pollers(1),
           max_pollers(2),
           cq_timeout_msec(10000) {}
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 4738e02..ffb5a77 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -296,6 +296,9 @@
 /* Timeout in milliseconds to use for calls to the grpclb load balancer.
    If 0 or unset, the balancer calls will have no deadline. */
 #define GRPC_ARG_GRPCLB_CALL_TIMEOUT_MS "grpc.grpclb_timeout_ms"
+/** If non-zero, grpc server's cronet compression workaround will be enabled */
+#define GRPC_ARG_WORKAROUND_CRONET_COMPRESSION \
+  "grpc.workaround.cronet_compression"
 /** \} */
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a
@@ -589,7 +592,7 @@
 /** Specifies the type of APIs to use to pop events from the completion queue */
 typedef enum {
   /** Events are popped out by calling grpc_completion_queue_next() API ONLY */
-  GRPC_CQ_NEXT = 1,
+  GRPC_CQ_NEXT,
 
   /** Events are popped out by calling grpc_completion_queue_pluck() API ONLY*/
   GRPC_CQ_PLUCK
diff --git a/include/grpc/support/workaround_list.h b/include/grpc/support/workaround_list.h
new file mode 100644
index 0000000..6a8aa1f
--- /dev/null
+++ b/include/grpc/support/workaround_list.h
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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 GRPC_SUPPORT_WORKAROUND_LIST_H
+#define GRPC_SUPPORT_WORKAROUND_LIST_H
+
+/* The list of IDs of server workarounds currently maintained by gRPC. For
+ * explanation and detailed descriptions of workarounds, see
+ * /docs/workarounds.md
+ */
+typedef enum {
+  GRPC_WORKAROUND_ID_CRONET_COMPRESSION = 0,
+  GRPC_MAX_WORKAROUND_ID
+} grpc_workaround_list;
+
+#endif
diff --git a/package.xml b/package.xml
index e70321a..bb8617f 100644
--- a/package.xml
+++ b/package.xml
@@ -163,6 +163,7 @@
     <file baseinstalldir="/" name="include/grpc/slice.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/slice_buffer.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/status.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/support/workaround_list.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer_reader.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/compression_types.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/connectivity_state.h" role="src" />
@@ -398,6 +399,8 @@
     <file baseinstalldir="/" name="src/core/ext/census/tracing.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_utils.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" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.c" role="src" />
@@ -425,6 +428,7 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/ev_epollsig_linux.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/ev_poll_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/ev_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/ev_windows.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/executor.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iocp_windows.c" role="src" />
@@ -642,6 +646,8 @@
     <file baseinstalldir="/" name="src/core/ext/census/tracing.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/max_age/max_age_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/message_size/message_size_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/filters/workarounds/workaround_utils.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" />
     <file baseinstalldir="/" name="third_party/boringssl/crypto/asn1/asn1_locl.h" role="src" />
diff --git a/src/compiler/config.h b/src/compiler/config.h
index ba44cd8..fd1400c 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -96,4 +96,11 @@
 }  // namespace protobuf
 }  // namespace grpc
 
+namespace grpc_cpp_generator {
+
+static const char* const kCppGeneratorMessageHeaderExt = ".pb.h";
+static const char* const kCppGeneratorServiceHeaderExt = ".grpc.pb.h";
+
+}  // namespace grpc_cpp_generator
+
 #endif  // SRC_COMPILER_CONFIG_H
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index a1a0258..7a2c44f 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -40,9 +40,6 @@
 namespace grpc_cpp_generator {
 namespace {
 
-grpc::string message_header_ext() { return ".pb.h"; }
-grpc::string service_header_ext() { return ".grpc.pb.h"; }
-
 template <class T>
 grpc::string as_string(T x) {
   std::ostringstream out;
@@ -113,7 +110,7 @@
     vars["filename"] = file->filename();
     vars["filename_identifier"] = FilenameIdentifier(file->filename());
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = message_header_ext();
+    vars["message_header_ext"] = kCppGeneratorMessageHeaderExt;
 
     printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
@@ -128,6 +125,7 @@
     printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
     printer->Print(vars, "\n");
     printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+    printer->Print(vars, file->additional_headers().c_str());
     printer->Print(vars, "\n");
   }
   return output;
@@ -1039,8 +1037,8 @@
 
     vars["filename"] = file->filename();
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = message_header_ext();
-    vars["service_header_ext"] = service_header_ext();
+    vars["message_header_ext"] = kCppGeneratorMessageHeaderExt;
+    vars["service_header_ext"] = kCppGeneratorServiceHeaderExt;
 
     printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
@@ -1049,7 +1047,6 @@
 
     printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
     printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
-    printer->Print(vars, file->additional_headers().c_str());
     printer->Print(vars, "\n");
   }
   return output;
@@ -1425,8 +1422,8 @@
 
     vars["filename"] = file->filename();
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = message_header_ext();
-    vars["service_header_ext"] = service_header_ext();
+    vars["message_header_ext"] = kCppGeneratorMessageHeaderExt;
+    vars["service_header_ext"] = kCppGeneratorServiceHeaderExt;
 
     printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
new file mode 100644
index 0000000..7fb75e3
--- /dev/null
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c
@@ -0,0 +1,223 @@
+//
+// Copyright 2017, 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/filters/workarounds/workaround_cronet_compression_filter.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+
+#include "src/core/ext/filters/workarounds/workaround_utils.h"
+#include "src/core/lib/channel/channel_stack_builder.h"
+#include "src/core/lib/surface/channel_init.h"
+#include "src/core/lib/transport/metadata.h"
+
+typedef struct call_data {
+  // Receive closures are chained: we inject this closure as the
+  // recv_initial_metadata_ready up-call on transport_stream_op, and remember to
+  // call our next_recv_initial_metadata_ready member after handling it.
+  grpc_closure recv_initial_metadata_ready;
+  // Used by recv_initial_metadata_ready.
+  grpc_metadata_batch* recv_initial_metadata;
+  // Original recv_initial_metadata_ready callback, invoked after our own.
+  grpc_closure* next_recv_initial_metadata_ready;
+
+  // Marks whether the workaround is active
+  bool workaround_active;
+} call_data;
+
+// Find the user agent metadata element in the batch
+static bool get_user_agent_mdelem(const grpc_metadata_batch* batch,
+                                  grpc_mdelem* md) {
+  if (batch->idx.named.user_agent != NULL) {
+    *md = batch->idx.named.user_agent->md;
+    return true;
+  }
+  return false;
+}
+
+// Callback invoked when we receive an initial metadata.
+static void recv_initial_metadata_ready(grpc_exec_ctx* exec_ctx,
+                                        void* user_data, grpc_error* error) {
+  grpc_call_element* elem = user_data;
+  call_data* calld = elem->call_data;
+
+  if (GRPC_ERROR_NONE == error) {
+    grpc_mdelem md;
+    if (get_user_agent_mdelem(calld->recv_initial_metadata, &md)) {
+      grpc_workaround_user_agent_md* user_agent_md = grpc_parse_user_agent(md);
+      if (user_agent_md
+              ->workaround_active[GRPC_WORKAROUND_ID_CRONET_COMPRESSION]) {
+        calld->workaround_active = true;
+      }
+    }
+  }
+
+  // Invoke the next callback.
+  grpc_closure_run(exec_ctx, calld->next_recv_initial_metadata_ready,
+                   GRPC_ERROR_REF(error));
+}
+
+// Start transport stream op.
+static void start_transport_stream_op_batch(
+    grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
+    grpc_transport_stream_op_batch* op) {
+  call_data* calld = elem->call_data;
+
+  // Inject callback for receiving initial metadata
+  if (op->recv_initial_metadata) {
+    calld->next_recv_initial_metadata_ready =
+        op->payload->recv_initial_metadata.recv_initial_metadata_ready;
+    op->payload->recv_initial_metadata.recv_initial_metadata_ready =
+        &calld->recv_initial_metadata_ready;
+    calld->recv_initial_metadata =
+        op->payload->recv_initial_metadata.recv_initial_metadata;
+  }
+
+  if (op->send_message) {
+    /* Send message happens after client's user-agent (initial metadata) is
+     * received, so workaround_active must be set already */
+    if (calld->workaround_active) {
+      op->payload->send_message.send_message->flags |= GRPC_WRITE_NO_COMPRESS;
+    }
+  }
+
+  // Chain to the next filter.
+  grpc_call_next_op(exec_ctx, elem, op);
+}
+
+// Constructor for call_data.
+static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
+                                  grpc_call_element* elem,
+                                  const grpc_call_element_args* args) {
+  call_data* calld = elem->call_data;
+  calld->next_recv_initial_metadata_ready = NULL;
+  calld->workaround_active = false;
+  grpc_closure_init(&calld->recv_initial_metadata_ready,
+                    recv_initial_metadata_ready, elem,
+                    grpc_schedule_on_exec_ctx);
+  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_final_info* final_info,
+                              grpc_closure* ignored) {}
+
+// Constructor for channel_data.
+static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
+                                     grpc_channel_element* elem,
+                                     grpc_channel_element_args* args) {
+  return GRPC_ERROR_NONE;
+}
+
+// Destructor for channel_data.
+static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
+                                 grpc_channel_element* elem) {}
+
+// Parse the user agent
+static bool parse_user_agent(grpc_mdelem md) {
+  const char grpc_objc_specifier[] = "grpc-objc/";
+  const size_t grpc_objc_specifier_len = sizeof(grpc_objc_specifier) - 1;
+  const char cronet_specifier[] = "cronet_http";
+  const size_t cronet_specifier_len = sizeof(cronet_specifier) - 1;
+
+  char* user_agent_str = grpc_slice_to_c_string(GRPC_MDVALUE(md));
+  bool grpc_objc_specifier_seen = false;
+  bool cronet_specifier_seen = false;
+  char *major_version_str = user_agent_str, *minor_version_str;
+  long major_version, minor_version;
+
+  char* head = strtok(user_agent_str, " ");
+  while (head != NULL) {
+    if (!grpc_objc_specifier_seen &&
+        0 == strncmp(head, grpc_objc_specifier, grpc_objc_specifier_len)) {
+      major_version_str = head + grpc_objc_specifier_len;
+      grpc_objc_specifier_seen = true;
+    } else if (grpc_objc_specifier_seen &&
+               0 == strncmp(head, cronet_specifier, cronet_specifier_len)) {
+      cronet_specifier_seen = true;
+      break;
+    }
+
+    head = strtok(NULL, " ");
+  }
+  if (grpc_objc_specifier_seen) {
+    major_version_str = strtok(major_version_str, ".");
+    minor_version_str = strtok(NULL, ".");
+    major_version = atol(major_version_str);
+    minor_version = atol(minor_version_str);
+  }
+
+  gpr_free(user_agent_str);
+  return (grpc_objc_specifier_seen && cronet_specifier_seen &&
+          (major_version < 1 || (major_version == 1 && minor_version <= 3)));
+}
+
+const grpc_channel_filter grpc_workaround_cronet_compression_filter = {
+    start_transport_stream_op_batch,
+    grpc_channel_next_op,
+    sizeof(call_data),
+    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,
+    grpc_channel_next_get_info,
+    "workaround_cronet_compression"};
+
+static bool register_workaround_cronet_compression(
+    grpc_exec_ctx* exec_ctx, grpc_channel_stack_builder* builder, void* arg) {
+  const grpc_channel_args* channel_args =
+      grpc_channel_stack_builder_get_channel_arguments(builder);
+  const grpc_arg* a = grpc_channel_args_find(
+      channel_args, GRPC_ARG_WORKAROUND_CRONET_COMPRESSION);
+  if (a == NULL) {
+    return true;
+  }
+  if (grpc_channel_arg_get_bool(a, false) == false) {
+    return true;
+  }
+  return grpc_channel_stack_builder_prepend_filter(
+      builder, &grpc_workaround_cronet_compression_filter, NULL, NULL);
+}
+
+void grpc_workaround_cronet_compression_filter_init(void) {
+  grpc_channel_init_register_stage(
+      GRPC_SERVER_CHANNEL, GRPC_WORKAROUND_PRIORITY_HIGH,
+      register_workaround_cronet_compression, NULL);
+  grpc_register_workaround(GRPC_WORKAROUND_ID_CRONET_COMPRESSION,
+                           parse_user_agent);
+}
+
+void grpc_workaround_cronet_compression_filter_shutdown(void) {}
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
new file mode 100644
index 0000000..58c79a0
--- /dev/null
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
@@ -0,0 +1,40 @@
+//
+// Copyright 2017, 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_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H
+#define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H
+
+#include "src/core/lib/channel/channel_stack.h"
+
+extern const grpc_channel_filter grpc_workaround_cronet_compression_filter;
+
+#endif /* GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H \
+        */
diff --git a/src/core/ext/filters/workarounds/workaround_utils.c b/src/core/ext/filters/workarounds/workaround_utils.c
new file mode 100644
index 0000000..1c56538
--- /dev/null
+++ b/src/core/ext/filters/workarounds/workaround_utils.c
@@ -0,0 +1,65 @@
+//
+// Copyright 2017, 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/filters/workarounds/workaround_utils.h"
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+user_agent_parser ua_parser[GRPC_MAX_WORKAROUND_ID];
+
+static void destroy_user_agent_md(void *user_agent_md) {
+  gpr_free(user_agent_md);
+}
+
+grpc_workaround_user_agent_md *grpc_parse_user_agent(grpc_mdelem md) {
+  grpc_workaround_user_agent_md *user_agent_md =
+      (grpc_workaround_user_agent_md *)grpc_mdelem_get_user_data(
+          md, destroy_user_agent_md);
+
+  if (NULL != user_agent_md) {
+    return user_agent_md;
+  }
+  user_agent_md = gpr_malloc(sizeof(grpc_workaround_user_agent_md));
+  for (int i = 0; i < GRPC_MAX_WORKAROUND_ID; i++) {
+    if (ua_parser[i]) {
+      user_agent_md->workaround_active[i] = ua_parser[i](md);
+    }
+  }
+  grpc_mdelem_set_user_data(md, destroy_user_agent_md, (void *)user_agent_md);
+
+  return user_agent_md;
+}
+
+void grpc_register_workaround(uint32_t id, user_agent_parser parser) {
+  GPR_ASSERT(id < GRPC_MAX_WORKAROUND_ID);
+  ua_parser[id] = parser;
+}
diff --git a/src/core/ext/filters/workarounds/workaround_utils.h b/src/core/ext/filters/workarounds/workaround_utils.h
new file mode 100644
index 0000000..7cd70c1
--- /dev/null
+++ b/src/core/ext/filters/workarounds/workaround_utils.h
@@ -0,0 +1,52 @@
+//
+// Copyright 2017, 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_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H
+#define GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H
+
+#include <grpc/support/workaround_list.h>
+
+#include "src/core/lib/transport/metadata.h"
+
+#define GRPC_WORKAROUND_PRIORITY_HIGH 10001
+#define GRPC_WORKAROUND_PROIRITY_LOW 9999
+
+typedef struct grpc_workaround_user_agent_md {
+  bool workaround_active[GRPC_MAX_WORKAROUND_ID];
+} grpc_workaround_user_agent_md;
+
+grpc_workaround_user_agent_md *grpc_parse_user_agent(grpc_mdelem md);
+
+typedef bool (*user_agent_parser)(grpc_mdelem);
+
+void grpc_register_workaround(uint32_t id, user_agent_parser parser);
+
+#endif
diff --git a/src/core/lib/channel/channel_args.c b/src/core/lib/channel/channel_args.c
index 238d176..247b134 100644
--- a/src/core/lib/channel/channel_args.c
+++ b/src/core/lib/channel/channel_args.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <limits.h>
 #include <string.h>
 
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index 5f2c989..685581b 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -769,7 +769,7 @@
               GRPC_ERROR_INT_ERRNO, err),
           GRPC_ERROR_STR_OS_ERROR,
           grpc_slice_from_static_string(strerror(err))),
-      GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string(call_name));
+      GRPC_ERROR_STR_SYSCALL, grpc_slice_from_copied_string(call_name));
 }
 
 #ifdef GPR_WINDOWS
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.c b/src/core/lib/iomgr/ev_epollsig_linux.c
index 52362a6..92c555b 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.c
+++ b/src/core/lib/iomgr/ev_epollsig_linux.c
@@ -65,9 +65,9 @@
 
 #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1)
 
-#define GRPC_POLLING_TRACE(fmt, ...)        \
+#define GRPC_POLLING_TRACE(...)             \
   if (GRPC_TRACER_ON(grpc_polling_trace)) { \
-    gpr_log(GPR_INFO, (fmt), __VA_ARGS__);  \
+    gpr_log(GPR_INFO, __VA_ARGS__);         \
   }
 
 /* Uncomment the following to enable extra checks on poll_object operations */
@@ -732,7 +732,7 @@
      it right now. Note that since we do an anticipatory mpscq_pop every poll
      loop, it's ok if we miss the wakeup here, as we'll get the work item when
      the next poller enters anyway. */
-  if (current_pollers > min_current_pollers_for_wakeup) {
+  if (current_pollers >= min_current_pollers_for_wakeup) {
     GRPC_LOG_IF_ERROR("workqueue_wakeup_fd",
                       grpc_wakeup_fd_wakeup(&pi->workqueue_wakeup_fd));
   }
@@ -1332,7 +1332,13 @@
     gpr_mpscq_node *n = gpr_mpscq_pop(&pi->workqueue_items);
     gpr_mu_unlock(&pi->workqueue_read_mu);
     if (n != NULL) {
-      if (gpr_atm_full_fetch_add(&pi->workqueue_item_count, -1) > 1) {
+      gpr_atm remaining =
+          gpr_atm_full_fetch_add(&pi->workqueue_item_count, -1) - 1;
+      GRPC_POLLING_TRACE(
+          "maybe_do_workqueue_work: pi: %p: got closure %p, remaining = "
+          "%" PRIdPTR,
+          pi, n, remaining);
+      if (remaining > 0) {
         workqueue_maybe_wakeup(pi);
       }
       grpc_closure *c = (grpc_closure *)n;
@@ -1347,8 +1353,13 @@
       /* n == NULL might mean there's work but it's not available to be popped
        * yet - try to ensure another workqueue wakes up to check shortly if so
        */
+      GRPC_POLLING_TRACE(
+          "maybe_do_workqueue_work: pi: %p: more to do, but not yet", pi);
       workqueue_maybe_wakeup(pi);
     }
+  } else {
+    GRPC_POLLING_TRACE("maybe_do_workqueue_work: pi: %p: read already locked",
+                       pi);
   }
   return false;
 }
@@ -1411,7 +1422,10 @@
   /* If we get some workqueue work to do, it might end up completing an item on
      the completion queue, so there's no need to poll... so we skip that and
      redo the complete loop to verify */
+  GRPC_POLLING_TRACE("pollset_work: pollset: %p, worker %p, pi %p", pollset,
+                     worker, pi);
   if (!maybe_do_workqueue_work(exec_ctx, pi)) {
+    GRPC_POLLING_TRACE("pollset_work: begins");
     gpr_atm_no_barrier_fetch_add(&pi->poller_count, 1);
     g_current_thread_polling_island = pi;
 
@@ -1472,6 +1486,7 @@
 
     g_current_thread_polling_island = NULL;
     gpr_atm_no_barrier_fetch_add(&pi->poller_count, -1);
+    GRPC_POLLING_TRACE("pollset_work: ends");
   }
 
   GPR_ASSERT(pi != NULL);
diff --git a/src/core/lib/iomgr/ev_windows.c b/src/core/lib/iomgr/ev_windows.c
new file mode 100644
index 0000000..7bf7327
--- /dev/null
+++ b/src/core/lib/iomgr/ev_windows.c
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_WINSOCK_SOCKET
+
+#include "src/core/lib/debug/trace.h"
+
+grpc_tracer_flag grpc_polling_trace =
+    GRPC_TRACER_INITIALIZER(false); /* Disabled by default */
+
+#endif  // GRPC_WINSOCK_SOCKET
diff --git a/src/core/lib/support/mpscq.c b/src/core/lib/support/mpscq.c
index 1015cc6..822abd0 100644
--- a/src/core/lib/support/mpscq.c
+++ b/src/core/lib/support/mpscq.c
@@ -46,11 +46,12 @@
   GPR_ASSERT(q->tail == &q->stub);
 }
 
-void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) {
+bool gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) {
   gpr_atm_no_barrier_store(&n->next, (gpr_atm)NULL);
   gpr_mpscq_node *prev =
       (gpr_mpscq_node *)gpr_atm_full_xchg(&q->head, (gpr_atm)n);
   gpr_atm_rel_store(&prev->next, (gpr_atm)n);
+  return prev == &q->stub;
 }
 
 gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) {
@@ -92,3 +93,25 @@
   *empty = false;
   return NULL;
 }
+
+void gpr_locked_mpscq_init(gpr_locked_mpscq *q) {
+  gpr_mpscq_init(&q->queue);
+  q->read_lock = GPR_SPINLOCK_INITIALIZER;
+}
+
+void gpr_locked_mpscq_destroy(gpr_locked_mpscq *q) {
+  gpr_mpscq_destroy(&q->queue);
+}
+
+bool gpr_locked_mpscq_push(gpr_locked_mpscq *q, gpr_mpscq_node *n) {
+  return gpr_mpscq_push(&q->queue, n);
+}
+
+gpr_mpscq_node *gpr_locked_mpscq_pop(gpr_locked_mpscq *q) {
+  if (gpr_spinlock_trylock(&q->read_lock)) {
+    gpr_mpscq_node *n = gpr_mpscq_pop(&q->queue);
+    gpr_spinlock_unlock(&q->read_lock);
+    return n;
+  }
+  return NULL;
+}
diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h
index 24c89f9..b3a1716 100644
--- a/src/core/lib/support/mpscq.h
+++ b/src/core/lib/support/mpscq.h
@@ -37,6 +37,7 @@
 #include <grpc/support/atm.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include "src/core/lib/support/spinlock.h"
 
 // Multiple-producer single-consumer lock free queue, based upon the
 // implementation from Dmitry Vyukov here:
@@ -58,12 +59,34 @@
 void gpr_mpscq_init(gpr_mpscq *q);
 void gpr_mpscq_destroy(gpr_mpscq *q);
 // Push a node
-void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n);
+// Thread safe - can be called from multiple threads concurrently
+// Returns true if this was possibly the first node (may return true
+// sporadically, will not return false sporadically)
+bool gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n);
 // Pop a node (returns NULL if no node is ready - which doesn't indicate that
 // the queue is empty!!)
+// Thread compatible - can only be called from one thread at a time
 gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q);
-
 // Pop a node; sets *empty to true if the queue is empty, or false if it is not
 gpr_mpscq_node *gpr_mpscq_pop_and_check_end(gpr_mpscq *q, bool *empty);
 
+// An mpscq with a spinlock: it's safe to pop from multiple threads, but doing
+// only one thread will succeed concurrently
+typedef struct gpr_locked_mpscq {
+  gpr_mpscq queue;
+  gpr_spinlock read_lock;
+} gpr_locked_mpscq;
+
+void gpr_locked_mpscq_init(gpr_locked_mpscq *q);
+void gpr_locked_mpscq_destroy(gpr_locked_mpscq *q);
+// Push a node
+// Thread safe - can be called from multiple threads concurrently
+// Returns true if this was possibly the first node (may return true
+// sporadically, will not return false sporadically)
+bool gpr_locked_mpscq_push(gpr_locked_mpscq *q, gpr_mpscq_node *n);
+// Pop a node (returns NULL if no node is ready - which doesn't indicate that
+// the queue is empty!!)
+// Thread safe - can be called from multiple threads concurrently
+gpr_mpscq_node *gpr_locked_mpscq_pop(gpr_locked_mpscq *q);
+
 #endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index df5b702..b0a4b1f 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -30,7 +30,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
-
 #include "src/core/lib/surface/completion_queue.h"
 
 #include <stdio.h>
@@ -45,6 +44,7 @@
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/core/lib/support/spinlock.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/call.h"
@@ -201,33 +201,68 @@
      .destroy = non_polling_poller_destroy},
 };
 
-/* Completion queue structure */
-struct grpc_completion_queue {
-  /** owned by pollset */
+typedef struct cq_vtable {
+  grpc_cq_completion_type cq_completion_type;
+  size_t (*size)();
+  void (*begin_op)(grpc_completion_queue *cc, void *tag);
+  void (*end_op)(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc, void *tag,
+                 grpc_error *error,
+                 void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
+                              grpc_cq_completion *storage),
+                 void *done_arg, grpc_cq_completion *storage);
+  grpc_event (*next)(grpc_completion_queue *cc, gpr_timespec deadline,
+                     void *reserved);
+  grpc_event (*pluck)(grpc_completion_queue *cc, void *tag,
+                      gpr_timespec deadline, void *reserved);
+} cq_vtable;
+
+/* Queue that holds the cq_completion_events. Internally uses gpr_mpscq queue
+ * (a lockfree multiproducer single consumer queue). It uses a queue_lock
+ * to support multiple consumers.
+ * Only used in completion queues whose completion_type is GRPC_CQ_NEXT */
+typedef struct grpc_cq_event_queue {
+  /* Spinlock to serialize consumers i.e pop() operations */
+  gpr_spinlock queue_lock;
+
+  gpr_mpscq queue;
+
+  /* A lazy counter of number of items in the queue. This is NOT atomically
+     incremented/decremented along with push/pop operations and hence is only
+     eventually consistent */
+  gpr_atm num_queue_items;
+} grpc_cq_event_queue;
+
+/* TODO: sreek Refactor this based on the completion_type. Put completion-type
+ * specific data in a different structure (and co-allocate memory for it along
+ * with completion queue + pollset )*/
+typedef struct cq_data {
   gpr_mu *mu;
 
-  grpc_cq_completion_type completion_type;
-
-  const cq_poller_vtable *poller_vtable;
-
-  /** completed events */
+  /** Completed events for completion-queues of type GRPC_CQ_PLUCK */
   grpc_cq_completion completed_head;
   grpc_cq_completion *completed_tail;
+
+  /** Completed events for completion-queues of type GRPC_CQ_NEXT */
+  grpc_cq_event_queue queue;
+
   /** Number of pending events (+1 if we're not shutdown) */
   gpr_refcount pending_events;
+
   /** Once owning_refs drops to zero, we will destroy the cq */
   gpr_refcount owning_refs;
-  /** counter of how many things have ever been queued on this completion queue
+
+  /** Counter of how many things have ever been queued on this completion queue
       useful for avoiding locks to check the queue */
   gpr_atm things_queued_ever;
+
   /** 0 initially, 1 once we've begun shutting down */
-  int shutdown;
+  gpr_atm shutdown;
   int shutdown_called;
+
   int is_server_cq;
-  /** Can the server cq accept incoming channels */
-  /* TODO: sreek - This will no longer be needed. Use polling_type set */
-  int is_non_listening_server_cq;
+
   int num_pluckers;
+  int num_polls;
   plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
   grpc_closure pollset_shutdown_done;
 
@@ -236,8 +271,61 @@
   size_t outstanding_tag_count;
   size_t outstanding_tag_capacity;
 #endif
+} cq_data;
 
-  grpc_completion_queue *next_free;
+/* Completion queue structure */
+struct grpc_completion_queue {
+  cq_data data;
+  const cq_vtable *vtable;
+  const cq_poller_vtable *poller_vtable;
+};
+
+/* Forward declarations */
+static void cq_finish_shutdown(grpc_exec_ctx *exec_ctx,
+                               grpc_completion_queue *cc);
+
+static size_t cq_size(grpc_completion_queue *cc);
+
+static void cq_begin_op(grpc_completion_queue *cc, void *tag);
+
+static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
+                               grpc_completion_queue *cc, void *tag,
+                               grpc_error *error,
+                               void (*done)(grpc_exec_ctx *exec_ctx,
+                                            void *done_arg,
+                                            grpc_cq_completion *storage),
+                               void *done_arg, grpc_cq_completion *storage);
+
+static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
+                                grpc_completion_queue *cc, void *tag,
+                                grpc_error *error,
+                                void (*done)(grpc_exec_ctx *exec_ctx,
+                                             void *done_arg,
+                                             grpc_cq_completion *storage),
+                                void *done_arg, grpc_cq_completion *storage);
+
+static grpc_event cq_next(grpc_completion_queue *cc, gpr_timespec deadline,
+                          void *reserved);
+
+static grpc_event cq_pluck(grpc_completion_queue *cc, void *tag,
+                           gpr_timespec deadline, void *reserved);
+
+/* Completion queue vtables based on the completion-type */
+static const cq_vtable g_cq_vtable[] = {
+    /* GRPC_CQ_NEXT */
+    {.cq_completion_type = GRPC_CQ_NEXT,
+     .size = cq_size,
+     .begin_op = cq_begin_op,
+     .end_op = cq_end_op_for_next,
+     .next = cq_next,
+     .pluck = NULL},
+    /* GRPC_CQ_PLUCK */
+    {.cq_completion_type = GRPC_CQ_PLUCK,
+     .size = cq_size,
+     .begin_op = cq_begin_op,
+     .end_op = cq_end_op_for_pluck,
+     .next = NULL,
+     .pluck = cq_pluck},
 };
 
 #define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1))
@@ -258,6 +346,47 @@
 static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
                                      grpc_error *error);
 
+static void cq_event_queue_init(grpc_cq_event_queue *q) {
+  gpr_mpscq_init(&q->queue);
+  q->queue_lock = GPR_SPINLOCK_INITIALIZER;
+  gpr_atm_no_barrier_store(&q->num_queue_items, 0);
+}
+
+static void cq_event_queue_destroy(grpc_cq_event_queue *q) {
+  gpr_mpscq_destroy(&q->queue);
+}
+
+static void cq_event_queue_push(grpc_cq_event_queue *q, grpc_cq_completion *c) {
+  gpr_mpscq_push(&q->queue, (gpr_mpscq_node *)c);
+  gpr_atm_no_barrier_fetch_add(&q->num_queue_items, 1);
+}
+
+static grpc_cq_completion *cq_event_queue_pop(grpc_cq_event_queue *q) {
+  grpc_cq_completion *c = NULL;
+  if (gpr_spinlock_trylock(&q->queue_lock)) {
+    c = (grpc_cq_completion *)gpr_mpscq_pop(&q->queue);
+    gpr_spinlock_unlock(&q->queue_lock);
+  }
+
+  if (c) {
+    gpr_atm_no_barrier_fetch_add(&q->num_queue_items, -1);
+  }
+
+  return c;
+}
+
+/* Note: The counter is not incremented/decremented atomically with push/pop.
+ * The count is only eventually consistent */
+static long cq_event_queue_num_items(grpc_cq_event_queue *q) {
+  return (long)gpr_atm_no_barrier_load(&q->num_queue_items);
+}
+
+static size_t cq_size(grpc_completion_queue *cc) {
+  /* Size of the completion queue and the size of the pollset whose memory is
+     allocated right after that of completion queue */
+  return sizeof(grpc_completion_queue) + cc->poller_vtable->size();
+}
+
 grpc_completion_queue *grpc_completion_queue_create_internal(
     grpc_cq_completion_type completion_type,
     grpc_cq_polling_type polling_type) {
@@ -270,35 +399,40 @@
       "polling_type=%d)",
       2, (completion_type, polling_type));
 
+  const cq_vtable *vtable = &g_cq_vtable[completion_type];
   const cq_poller_vtable *poller_vtable =
       &g_poller_vtable_by_poller_type[polling_type];
 
   cc = gpr_zalloc(sizeof(grpc_completion_queue) + poller_vtable->size());
-  poller_vtable->init(POLLSET_FROM_CQ(cc), &cc->mu);
-#ifndef NDEBUG
-  cc->outstanding_tags = NULL;
-  cc->outstanding_tag_capacity = 0;
-#endif
+  cq_data *cqd = &cc->data;
 
-  cc->completion_type = completion_type;
+  cc->vtable = vtable;
   cc->poller_vtable = poller_vtable;
 
-  /* Initial ref is dropped by grpc_completion_queue_shutdown */
-  gpr_ref_init(&cc->pending_events, 1);
-  /* One for destroy(), one for pollset_shutdown */
-  gpr_ref_init(&cc->owning_refs, 2);
-  cc->completed_tail = &cc->completed_head;
-  cc->completed_head.next = (uintptr_t)cc->completed_tail;
-  cc->shutdown = 0;
-  cc->shutdown_called = 0;
-  cc->is_server_cq = 0;
-  cc->is_non_listening_server_cq = 0;
-  cc->num_pluckers = 0;
-  gpr_atm_no_barrier_store(&cc->things_queued_ever, 0);
+  poller_vtable->init(POLLSET_FROM_CQ(cc), &cc->data.mu);
+
 #ifndef NDEBUG
-  cc->outstanding_tag_count = 0;
+  cqd->outstanding_tags = NULL;
+  cqd->outstanding_tag_capacity = 0;
 #endif
-  grpc_closure_init(&cc->pollset_shutdown_done, on_pollset_shutdown_done, cc,
+
+  /* Initial ref is dropped by grpc_completion_queue_shutdown */
+  gpr_ref_init(&cqd->pending_events, 1);
+  /* One for destroy(), one for pollset_shutdown */
+  gpr_ref_init(&cqd->owning_refs, 2);
+  cqd->completed_tail = &cqd->completed_head;
+  cqd->completed_head.next = (uintptr_t)cqd->completed_tail;
+  gpr_atm_no_barrier_store(&cqd->shutdown, 0);
+  cqd->shutdown_called = 0;
+  cqd->is_server_cq = 0;
+  cqd->num_pluckers = 0;
+  cqd->num_polls = 0;
+  gpr_atm_no_barrier_store(&cqd->things_queued_ever, 0);
+#ifndef NDEBUG
+  cqd->outstanding_tag_count = 0;
+#endif
+  cq_event_queue_init(&cqd->queue);
+  grpc_closure_init(&cqd->pollset_shutdown_done, on_pollset_shutdown_done, cc,
                     grpc_schedule_on_exec_ctx);
 
   GPR_TIMER_END("grpc_completion_queue_create_internal", 0);
@@ -307,18 +441,28 @@
 }
 
 grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc) {
-  return cc->completion_type;
+  return cc->vtable->cq_completion_type;
+}
+
+int grpc_get_cq_poll_num(grpc_completion_queue *cc) {
+  int cur_num_polls;
+  gpr_mu_lock(cc->data.mu);
+  cur_num_polls = cc->data.num_polls;
+  gpr_mu_unlock(cc->data.mu);
+  return cur_num_polls;
 }
 
 #ifdef GRPC_CQ_REF_COUNT_DEBUG
 void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
                           const char *file, int line) {
+  cq_data *cqd = &cc->data;
   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p   ref %d -> %d %s", cc,
-          (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason);
+          (int)cqd->owning_refs.count, (int)cqd->owning_refs.count + 1, reason);
 #else
 void grpc_cq_internal_ref(grpc_completion_queue *cc) {
+  cq_data *cqd = &cc->data;
 #endif
-  gpr_ref(&cc->owning_refs);
+  gpr_ref(&cqd->owning_refs);
 }
 
 static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
@@ -328,63 +472,160 @@
 }
 
 #ifdef GRPC_CQ_REF_COUNT_DEBUG
-void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
-                            const char *reason, const char *file, int line) {
+void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason,
+                            const char *file, int line) {
+  cq_data *cqd = &cc->data;
   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc,
-          (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason);
+          (int)cqd->owning_refs.count, (int)cqd->owning_refs.count - 1, reason);
 #else
 void grpc_cq_internal_unref(grpc_exec_ctx *exec_ctx,
                             grpc_completion_queue *cc) {
+  cq_data *cqd = &cc->data;
 #endif
-  if (gpr_unref(&cc->owning_refs)) {
-    GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head);
+  if (gpr_unref(&cqd->owning_refs)) {
+    GPR_ASSERT(cqd->completed_head.next == (uintptr_t)&cqd->completed_head);
     cc->poller_vtable->destroy(exec_ctx, POLLSET_FROM_CQ(cc));
+    cq_event_queue_destroy(&cqd->queue);
 #ifndef NDEBUG
-    gpr_free(cc->outstanding_tags);
+    gpr_free(cqd->outstanding_tags);
 #endif
     gpr_free(cc);
   }
 }
 
-void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
+static void cq_begin_op(grpc_completion_queue *cc, void *tag) {
+  cq_data *cqd = &cc->data;
 #ifndef NDEBUG
-  gpr_mu_lock(cc->mu);
-  GPR_ASSERT(!cc->shutdown_called);
-  if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) {
-    cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity);
-    cc->outstanding_tags =
-        gpr_realloc(cc->outstanding_tags, sizeof(*cc->outstanding_tags) *
-                                              cc->outstanding_tag_capacity);
+  gpr_mu_lock(cqd->mu);
+  GPR_ASSERT(!cqd->shutdown_called);
+  if (cqd->outstanding_tag_count == cqd->outstanding_tag_capacity) {
+    cqd->outstanding_tag_capacity =
+        GPR_MAX(4, 2 * cqd->outstanding_tag_capacity);
+    cqd->outstanding_tags =
+        gpr_realloc(cqd->outstanding_tags, sizeof(*cqd->outstanding_tags) *
+                                               cqd->outstanding_tag_capacity);
   }
-  cc->outstanding_tags[cc->outstanding_tag_count++] = tag;
-  gpr_mu_unlock(cc->mu);
+  cqd->outstanding_tags[cqd->outstanding_tag_count++] = tag;
+  gpr_mu_unlock(cqd->mu);
 #endif
-  gpr_ref(&cc->pending_events);
+  gpr_ref(&cqd->pending_events);
 }
 
-/* Signal the end of an operation - if this is the last waiting-to-be-queued
-   event, then enter shutdown mode */
-/* Queue a GRPC_OP_COMPLETED operation */
-void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
-                    void *tag, grpc_error *error,
-                    void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
-                                 grpc_cq_completion *storage),
-                    void *done_arg, grpc_cq_completion *storage) {
-  int shutdown;
-  int i;
-  grpc_pollset_worker *pluck_worker;
+void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
+  cc->vtable->begin_op(cc, tag);
+}
+
 #ifndef NDEBUG
+static void cq_check_tag(grpc_completion_queue *cc, void *tag, bool lock_cq) {
+  cq_data *cqd = &cc->data;
   int found = 0;
+  if (lock_cq) {
+    gpr_mu_lock(cqd->mu);
+  }
+
+  for (int i = 0; i < (int)cqd->outstanding_tag_count; i++) {
+    if (cqd->outstanding_tags[i] == tag) {
+      cqd->outstanding_tag_count--;
+      GPR_SWAP(void *, cqd->outstanding_tags[i],
+               cqd->outstanding_tags[cqd->outstanding_tag_count]);
+      found = 1;
+      break;
+    }
+  }
+
+  if (lock_cq) {
+    gpr_mu_unlock(cqd->mu);
+  }
+
+  GPR_ASSERT(found);
+}
+#else
+static void cq_check_tag(grpc_completion_queue *cc, void *tag, bool lock_cq) {}
 #endif
 
-  GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
+/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a completion
+ * type of GRPC_CQ_NEXT) */
+static void cq_end_op_for_next(grpc_exec_ctx *exec_ctx,
+                               grpc_completion_queue *cc, void *tag,
+                               grpc_error *error,
+                               void (*done)(grpc_exec_ctx *exec_ctx,
+                                            void *done_arg,
+                                            grpc_cq_completion *storage),
+                               void *done_arg, grpc_cq_completion *storage) {
+  GPR_TIMER_BEGIN("cq_end_op_for_next", 0);
+
   if (GRPC_TRACER_ON(grpc_api_trace) ||
       (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
        error != GRPC_ERROR_NONE)) {
     const char *errmsg = grpc_error_string(error);
     GRPC_API_TRACE(
-        "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, error=%s, done=%p, "
-        "done_arg=%p, storage=%p)",
+        "cq_end_op_for_next(exec_ctx=%p, cc=%p, tag=%p, error=%s, "
+        "done=%p, done_arg=%p, storage=%p)",
+        7, (exec_ctx, cc, tag, errmsg, done, done_arg, storage));
+    if (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
+        error != GRPC_ERROR_NONE) {
+      gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
+    }
+  }
+
+  cq_data *cqd = &cc->data;
+  int is_success = (error == GRPC_ERROR_NONE);
+
+  storage->tag = tag;
+  storage->done = done;
+  storage->done_arg = done_arg;
+  storage->next = (uintptr_t)(is_success);
+
+  cq_check_tag(cc, tag, true); /* Used in debug builds only */
+
+  /* Add the completion to the queue */
+  cq_event_queue_push(&cqd->queue, storage);
+  gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
+
+  int shutdown = gpr_unref(&cqd->pending_events);
+
+  gpr_mu_lock(cqd->mu);
+  if (!shutdown) {
+    grpc_error *kick_error = cc->poller_vtable->kick(POLLSET_FROM_CQ(cc), NULL);
+    gpr_mu_unlock(cqd->mu);
+
+    if (kick_error != GRPC_ERROR_NONE) {
+      const char *msg = grpc_error_string(kick_error);
+      gpr_log(GPR_ERROR, "Kick failed: %s", msg);
+
+      GRPC_ERROR_UNREF(kick_error);
+    }
+  } else {
+    cq_finish_shutdown(exec_ctx, cc);
+    gpr_mu_unlock(cqd->mu);
+  }
+
+  GPR_TIMER_END("cq_end_op_for_next", 0);
+
+  GRPC_ERROR_UNREF(error);
+}
+
+/* Queue a GRPC_OP_COMPLETED operation to a completion queue (with a completion
+ * type of GRPC_CQ_PLUCK) */
+static void cq_end_op_for_pluck(grpc_exec_ctx *exec_ctx,
+                                grpc_completion_queue *cc, void *tag,
+                                grpc_error *error,
+                                void (*done)(grpc_exec_ctx *exec_ctx,
+                                             void *done_arg,
+                                             grpc_cq_completion *storage),
+                                void *done_arg, grpc_cq_completion *storage) {
+  cq_data *cqd = &cc->data;
+  int is_success = (error == GRPC_ERROR_NONE);
+
+  GPR_TIMER_BEGIN("cq_end_op_for_pluck", 0);
+
+  if (GRPC_TRACER_ON(grpc_api_trace) ||
+      (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
+       error != GRPC_ERROR_NONE)) {
+    const char *errmsg = grpc_error_string(error);
+    GRPC_API_TRACE(
+        "cq_end_op_for_pluck(exec_ctx=%p, cc=%p, tag=%p, error=%s, "
+        "done=%p, done_arg=%p, storage=%p)",
         7, (exec_ctx, cc, tag, errmsg, done, done_arg, storage));
     if (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
         error != GRPC_ERROR_NONE) {
@@ -395,38 +636,32 @@
   storage->tag = tag;
   storage->done = done;
   storage->done_arg = done_arg;
-  storage->next = ((uintptr_t)&cc->completed_head) |
-                  ((uintptr_t)(error == GRPC_ERROR_NONE));
+  storage->next = ((uintptr_t)&cqd->completed_head) | ((uintptr_t)(is_success));
 
-  gpr_mu_lock(cc->mu);
-#ifndef NDEBUG
-  for (i = 0; i < (int)cc->outstanding_tag_count; i++) {
-    if (cc->outstanding_tags[i] == tag) {
-      cc->outstanding_tag_count--;
-      GPR_SWAP(void *, cc->outstanding_tags[i],
-               cc->outstanding_tags[cc->outstanding_tag_count]);
-      found = 1;
-      break;
-    }
-  }
-  GPR_ASSERT(found);
-#endif
-  shutdown = gpr_unref(&cc->pending_events);
-  gpr_atm_no_barrier_fetch_add(&cc->things_queued_ever, 1);
+  gpr_mu_lock(cqd->mu);
+  cq_check_tag(cc, tag, false); /* Used in debug builds only */
+
+  /* Add to the list of completions */
+  gpr_atm_no_barrier_fetch_add(&cqd->things_queued_ever, 1);
+  cqd->completed_tail->next =
+      ((uintptr_t)storage) | (1u & (uintptr_t)cqd->completed_tail->next);
+  cqd->completed_tail = storage;
+
+  int shutdown = gpr_unref(&cqd->pending_events);
   if (!shutdown) {
-    cc->completed_tail->next =
-        ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
-    cc->completed_tail = storage;
-    pluck_worker = NULL;
-    for (i = 0; i < cc->num_pluckers; i++) {
-      if (cc->pluckers[i].tag == tag) {
-        pluck_worker = *cc->pluckers[i].worker;
+    grpc_pollset_worker *pluck_worker = NULL;
+    for (int i = 0; i < cqd->num_pluckers; i++) {
+      if (cqd->pluckers[i].tag == tag) {
+        pluck_worker = *cqd->pluckers[i].worker;
         break;
       }
     }
+
     grpc_error *kick_error =
         cc->poller_vtable->kick(POLLSET_FROM_CQ(cc), pluck_worker);
-    gpr_mu_unlock(cc->mu);
+
+    gpr_mu_unlock(cqd->mu);
+
     if (kick_error != GRPC_ERROR_NONE) {
       const char *msg = grpc_error_string(kick_error);
       gpr_log(GPR_ERROR, "Kick failed: %s", msg);
@@ -434,22 +669,23 @@
       GRPC_ERROR_UNREF(kick_error);
     }
   } else {
-    cc->completed_tail->next =
-        ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
-    cc->completed_tail = storage;
-    GPR_ASSERT(!cc->shutdown);
-    GPR_ASSERT(cc->shutdown_called);
-    cc->shutdown = 1;
-    cc->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
-                                &cc->pollset_shutdown_done);
-    gpr_mu_unlock(cc->mu);
+    cq_finish_shutdown(exec_ctx, cc);
+    gpr_mu_unlock(cqd->mu);
   }
 
-  GPR_TIMER_END("grpc_cq_end_op", 0);
+  GPR_TIMER_END("cq_end_op_for_pluck", 0);
 
   GRPC_ERROR_UNREF(error);
 }
 
+void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
+                    void *tag, grpc_error *error,
+                    void (*done)(grpc_exec_ctx *exec_ctx, void *done_arg,
+                                 grpc_cq_completion *storage),
+                    void *done_arg, grpc_cq_completion *storage) {
+  cc->vtable->end_op(exec_ctx, cc, tag, error, done, done_arg, storage);
+}
+
 typedef struct {
   gpr_atm last_seen_things_queued_ever;
   grpc_completion_queue *cq;
@@ -462,23 +698,24 @@
 static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) {
   cq_is_finished_arg *a = arg;
   grpc_completion_queue *cq = a->cq;
+  cq_data *cqd = &cq->data;
   GPR_ASSERT(a->stolen_completion == NULL);
+
   gpr_atm current_last_seen_things_queued_ever =
-      gpr_atm_no_barrier_load(&cq->things_queued_ever);
+      gpr_atm_no_barrier_load(&cqd->things_queued_ever);
+
   if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) {
-    gpr_mu_lock(cq->mu);
     a->last_seen_things_queued_ever =
-        gpr_atm_no_barrier_load(&cq->things_queued_ever);
-    if (cq->completed_tail != &cq->completed_head) {
-      a->stolen_completion = (grpc_cq_completion *)cq->completed_head.next;
-      cq->completed_head.next = a->stolen_completion->next & ~(uintptr_t)1;
-      if (a->stolen_completion == cq->completed_tail) {
-        cq->completed_tail = &cq->completed_head;
-      }
-      gpr_mu_unlock(cq->mu);
+        gpr_atm_no_barrier_load(&cqd->things_queued_ever);
+
+    /* Pop a cq_completion from the queue. Returns NULL if the queue is empty
+     * might return NULL in some cases even if the queue is not empty; but that
+     * is ok and doesn't affect correctness. Might effect the tail latencies a
+     * bit) */
+    a->stolen_completion = cq_event_queue_pop(&cqd->queue);
+    if (a->stolen_completion != NULL) {
       return true;
     }
-    gpr_mu_unlock(cq->mu);
   }
   return !a->first_loop &&
          gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
@@ -488,16 +725,18 @@
 static void dump_pending_tags(grpc_completion_queue *cc) {
   if (!GRPC_TRACER_ON(grpc_trace_pending_tags)) return;
 
+  cq_data *cqd = &cc->data;
+
   gpr_strvec v;
   gpr_strvec_init(&v);
   gpr_strvec_add(&v, gpr_strdup("PENDING TAGS:"));
-  gpr_mu_lock(cc->mu);
-  for (size_t i = 0; i < cc->outstanding_tag_count; i++) {
+  gpr_mu_lock(cqd->mu);
+  for (size_t i = 0; i < cqd->outstanding_tag_count; i++) {
     char *s;
-    gpr_asprintf(&s, " %p", cc->outstanding_tags[i]);
+    gpr_asprintf(&s, " %p", cqd->outstanding_tags[i]);
     gpr_strvec_add(&v, s);
   }
-  gpr_mu_unlock(cc->mu);
+  gpr_mu_unlock(cqd->mu);
   char *out = gpr_strvec_flatten(&v, NULL);
   gpr_strvec_destroy(&v);
   gpr_log(GPR_DEBUG, "%s", out);
@@ -507,17 +746,11 @@
 static void dump_pending_tags(grpc_completion_queue *cc) {}
 #endif
 
-grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
-                                      gpr_timespec deadline, void *reserved) {
+static grpc_event cq_next(grpc_completion_queue *cc, gpr_timespec deadline,
+                          void *reserved) {
   grpc_event ret;
   gpr_timespec now;
-
-  if (cc->completion_type != GRPC_CQ_NEXT) {
-    gpr_log(GPR_ERROR,
-            "grpc_completion_queue_next() cannot be called on this completion "
-            "queue since its completion type is not GRPC_CQ_NEXT");
-    abort();
-  }
+  cq_data *cqd = &cc->data;
 
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
 
@@ -536,10 +769,10 @@
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
 
   GRPC_CQ_INTERNAL_REF(cc, "next");
-  gpr_mu_lock(cc->mu);
+
   cq_is_finished_arg is_finished_arg = {
       .last_seen_things_queued_ever =
-          gpr_atm_no_barrier_load(&cc->things_queued_ever),
+          gpr_atm_no_barrier_load(&cqd->things_queued_ever),
       .cq = cc,
       .deadline = deadline,
       .stolen_completion = NULL,
@@ -547,9 +780,11 @@
       .first_loop = true};
   grpc_exec_ctx exec_ctx =
       GRPC_EXEC_CTX_INITIALIZER(0, cq_is_next_finished, &is_finished_arg);
+
   for (;;) {
+    gpr_timespec iteration_deadline = deadline;
+
     if (is_finished_arg.stolen_completion != NULL) {
-      gpr_mu_unlock(cc->mu);
       grpc_cq_completion *c = is_finished_arg.stolen_completion;
       is_finished_arg.stolen_completion = NULL;
       ret.type = GRPC_OP_COMPLETE;
@@ -558,37 +793,59 @@
       c->done(&exec_ctx, c->done_arg, c);
       break;
     }
-    if (cc->completed_tail != &cc->completed_head) {
-      grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
-      cc->completed_head.next = c->next & ~(uintptr_t)1;
-      if (c == cc->completed_tail) {
-        cc->completed_tail = &cc->completed_head;
-      }
-      gpr_mu_unlock(cc->mu);
+
+    grpc_cq_completion *c = cq_event_queue_pop(&cqd->queue);
+
+    if (c != NULL) {
       ret.type = GRPC_OP_COMPLETE;
       ret.success = c->next & 1u;
       ret.tag = c->tag;
       c->done(&exec_ctx, c->done_arg, c);
       break;
+    } else {
+      /* If c == NULL it means either the queue is empty OR in an transient
+         inconsistent state. If it is the latter, we shold do a 0-timeout poll
+         so that the thread comes back quickly from poll to make a second
+         attempt at popping. Not doing this can potentially deadlock this thread
+         forever (if the deadline is infinity) */
+      if (cq_event_queue_num_items(&cqd->queue) > 0) {
+        iteration_deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
+      }
     }
-    if (cc->shutdown) {
-      gpr_mu_unlock(cc->mu);
+
+    if (gpr_atm_no_barrier_load(&cqd->shutdown)) {
+      /* Before returning, check if the queue has any items left over (since
+         gpr_mpscq_pop() can sometimes return NULL even if the queue is not
+         empty. If so, keep retrying but do not return GRPC_QUEUE_SHUTDOWN */
+      if (cq_event_queue_num_items(&cqd->queue) > 0) {
+        /* Go to the beginning of the loop. No point doing a poll because
+           (cc->shutdown == true) is only possible when there is no pending work
+           (i.e cc->pending_events == 0) and any outstanding grpc_cq_completion
+           events are already queued on this cq */
+        continue;
+      }
+
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_SHUTDOWN;
       break;
     }
+
     now = gpr_now(GPR_CLOCK_MONOTONIC);
     if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
-      gpr_mu_unlock(cc->mu);
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
       dump_pending_tags(cc);
       break;
     }
+
+    /* The main polling work happens in grpc_pollset_work */
+    gpr_mu_lock(cqd->mu);
+    cqd->num_polls++;
     grpc_error *err = cc->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cc),
-                                              NULL, now, deadline);
+                                              NULL, now, iteration_deadline);
+    gpr_mu_unlock(cqd->mu);
+
     if (err != GRPC_ERROR_NONE) {
-      gpr_mu_unlock(cc->mu);
       const char *msg = grpc_error_string(err);
       gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
 
@@ -600,6 +857,7 @@
     }
     is_finished_arg.first_loop = false;
   }
+
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cc, "next");
   grpc_exec_ctx_finish(&exec_ctx);
@@ -610,24 +868,30 @@
   return ret;
 }
 
+grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
+                                      gpr_timespec deadline, void *reserved) {
+  return cc->vtable->next(cc, deadline, reserved);
+}
+
 static int add_plucker(grpc_completion_queue *cc, void *tag,
                        grpc_pollset_worker **worker) {
-  if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
+  cq_data *cqd = &cc->data;
+  if (cqd->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
     return 0;
   }
-  cc->pluckers[cc->num_pluckers].tag = tag;
-  cc->pluckers[cc->num_pluckers].worker = worker;
-  cc->num_pluckers++;
+  cqd->pluckers[cqd->num_pluckers].tag = tag;
+  cqd->pluckers[cqd->num_pluckers].worker = worker;
+  cqd->num_pluckers++;
   return 1;
 }
 
 static void del_plucker(grpc_completion_queue *cc, void *tag,
                         grpc_pollset_worker **worker) {
-  int i;
-  for (i = 0; i < cc->num_pluckers; i++) {
-    if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) {
-      cc->num_pluckers--;
-      GPR_SWAP(plucker, cc->pluckers[i], cc->pluckers[cc->num_pluckers]);
+  cq_data *cqd = &cc->data;
+  for (int i = 0; i < cqd->num_pluckers; i++) {
+    if (cqd->pluckers[i].tag == tag && cqd->pluckers[i].worker == worker) {
+      cqd->num_pluckers--;
+      GPR_SWAP(plucker, cqd->pluckers[i], cqd->pluckers[cqd->num_pluckers]);
       return;
     }
   }
@@ -637,51 +901,47 @@
 static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) {
   cq_is_finished_arg *a = arg;
   grpc_completion_queue *cq = a->cq;
+  cq_data *cqd = &cq->data;
+
   GPR_ASSERT(a->stolen_completion == NULL);
   gpr_atm current_last_seen_things_queued_ever =
-      gpr_atm_no_barrier_load(&cq->things_queued_ever);
+      gpr_atm_no_barrier_load(&cqd->things_queued_ever);
   if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) {
-    gpr_mu_lock(cq->mu);
+    gpr_mu_lock(cqd->mu);
     a->last_seen_things_queued_ever =
-        gpr_atm_no_barrier_load(&cq->things_queued_ever);
+        gpr_atm_no_barrier_load(&cqd->things_queued_ever);
     grpc_cq_completion *c;
-    grpc_cq_completion *prev = &cq->completed_head;
+    grpc_cq_completion *prev = &cqd->completed_head;
     while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
-           &cq->completed_head) {
+           &cqd->completed_head) {
       if (c->tag == a->tag) {
         prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
-        if (c == cq->completed_tail) {
-          cq->completed_tail = prev;
+        if (c == cqd->completed_tail) {
+          cqd->completed_tail = prev;
         }
-        gpr_mu_unlock(cq->mu);
+        gpr_mu_unlock(cqd->mu);
         a->stolen_completion = c;
         return true;
       }
       prev = c;
     }
-    gpr_mu_unlock(cq->mu);
+    gpr_mu_unlock(cqd->mu);
   }
   return !a->first_loop &&
          gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
 }
 
-grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
-                                       gpr_timespec deadline, void *reserved) {
+static grpc_event cq_pluck(grpc_completion_queue *cc, void *tag,
+                           gpr_timespec deadline, void *reserved) {
   grpc_event ret;
   grpc_cq_completion *c;
   grpc_cq_completion *prev;
   grpc_pollset_worker *worker = NULL;
   gpr_timespec now;
+  cq_data *cqd = &cc->data;
 
   GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
 
-  if (cc->completion_type != GRPC_CQ_PLUCK) {
-    gpr_log(GPR_ERROR,
-            "grpc_completion_queue_pluck() cannot be called on this completion "
-            "queue since its completion type is not GRPC_CQ_PLUCK");
-    abort();
-  }
-
   if (GRPC_TRACER_ON(grpc_cq_pluck_trace)) {
     GRPC_API_TRACE(
         "grpc_completion_queue_pluck("
@@ -699,10 +959,10 @@
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
 
   GRPC_CQ_INTERNAL_REF(cc, "pluck");
-  gpr_mu_lock(cc->mu);
+  gpr_mu_lock(cqd->mu);
   cq_is_finished_arg is_finished_arg = {
       .last_seen_things_queued_ever =
-          gpr_atm_no_barrier_load(&cc->things_queued_ever),
+          gpr_atm_no_barrier_load(&cqd->things_queued_ever),
       .cq = cc,
       .deadline = deadline,
       .stolen_completion = NULL,
@@ -712,7 +972,7 @@
       GRPC_EXEC_CTX_INITIALIZER(0, cq_is_pluck_finished, &is_finished_arg);
   for (;;) {
     if (is_finished_arg.stolen_completion != NULL) {
-      gpr_mu_unlock(cc->mu);
+      gpr_mu_unlock(cqd->mu);
       c = is_finished_arg.stolen_completion;
       is_finished_arg.stolen_completion = NULL;
       ret.type = GRPC_OP_COMPLETE;
@@ -721,15 +981,15 @@
       c->done(&exec_ctx, c->done_arg, c);
       break;
     }
-    prev = &cc->completed_head;
+    prev = &cqd->completed_head;
     while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
-           &cc->completed_head) {
+           &cqd->completed_head) {
       if (c->tag == tag) {
         prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
-        if (c == cc->completed_tail) {
-          cc->completed_tail = prev;
+        if (c == cqd->completed_tail) {
+          cqd->completed_tail = prev;
         }
-        gpr_mu_unlock(cc->mu);
+        gpr_mu_unlock(cqd->mu);
         ret.type = GRPC_OP_COMPLETE;
         ret.success = c->next & 1u;
         ret.tag = c->tag;
@@ -738,8 +998,8 @@
       }
       prev = c;
     }
-    if (cc->shutdown) {
-      gpr_mu_unlock(cc->mu);
+    if (gpr_atm_no_barrier_load(&cqd->shutdown)) {
+      gpr_mu_unlock(cqd->mu);
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_SHUTDOWN;
       break;
@@ -749,7 +1009,7 @@
               "Too many outstanding grpc_completion_queue_pluck calls: maximum "
               "is %d",
               GRPC_MAX_COMPLETION_QUEUE_PLUCKERS);
-      gpr_mu_unlock(cc->mu);
+      gpr_mu_unlock(cqd->mu);
       memset(&ret, 0, sizeof(ret));
       /* TODO(ctiller): should we use a different result here */
       ret.type = GRPC_QUEUE_TIMEOUT;
@@ -759,19 +1019,21 @@
     now = gpr_now(GPR_CLOCK_MONOTONIC);
     if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
       del_plucker(cc, tag, &worker);
-      gpr_mu_unlock(cc->mu);
+      gpr_mu_unlock(cqd->mu);
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
       dump_pending_tags(cc);
       break;
     }
+
+    cqd->num_polls++;
     grpc_error *err = cc->poller_vtable->work(&exec_ctx, POLLSET_FROM_CQ(cc),
                                               &worker, now, deadline);
     if (err != GRPC_ERROR_NONE) {
       del_plucker(cc, tag, &worker);
-      gpr_mu_unlock(cc->mu);
+      gpr_mu_unlock(cqd->mu);
       const char *msg = grpc_error_string(err);
-      gpr_log(GPR_ERROR, "Completion queue next failed: %s", msg);
+      gpr_log(GPR_ERROR, "Completion queue pluck failed: %s", msg);
 
       GRPC_ERROR_UNREF(err);
       memset(&ret, 0, sizeof(ret));
@@ -793,26 +1055,48 @@
   return ret;
 }
 
+grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
+                                       gpr_timespec deadline, void *reserved) {
+  return cc->vtable->pluck(cc, tag, deadline, reserved);
+}
+
+/* Finishes the completion queue shutdown. This means that there are no more
+   completion events / tags expected from the completion queue
+   - Must be called under completion queue lock
+   - Must be called only once in completion queue's lifetime
+   - grpc_completion_queue_shutdown() MUST have been called before calling
+   this function */
+static void cq_finish_shutdown(grpc_exec_ctx *exec_ctx,
+                               grpc_completion_queue *cc) {
+  cq_data *cqd = &cc->data;
+
+  GPR_ASSERT(cqd->shutdown_called);
+  GPR_ASSERT(!gpr_atm_no_barrier_load(&cqd->shutdown));
+  gpr_atm_no_barrier_store(&cqd->shutdown, 1);
+
+  cc->poller_vtable->shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
+                              &cqd->pollset_shutdown_done);
+}
+
 /* Shutdown simply drops a ref that we reserved at creation time; if we drop
    to zero here, then enter shutdown mode and wake up any waiters */
 void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
   GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc));
-  gpr_mu_lock(cc->mu);
-  if (cc->shutdown_called) {
-    gpr_mu_unlock(cc->mu);
+  cq_data *cqd = &cc->data;
+
+  gpr_mu_lock(cqd->mu);
+  if (cqd->shutdown_called) {
+    gpr_mu_unlock(cqd->mu);
     GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
     return;
   }
-  cc->shutdown_called = 1;
-  if (gpr_unref(&cc->pending_events)) {
-    GPR_ASSERT(!cc->shutdown);
-    cc->shutdown = 1;
-    cc->poller_vtable->shutdown(&exec_ctx, POLLSET_FROM_CQ(cc),
-                                &cc->pollset_shutdown_done);
+  cqd->shutdown_called = 1;
+  if (gpr_unref(&cqd->pending_events)) {
+    cq_finish_shutdown(&exec_ctx, cc);
   }
-  gpr_mu_unlock(cc->mu);
+  gpr_mu_unlock(cqd->mu);
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
 }
@@ -821,6 +1105,13 @@
   GRPC_API_TRACE("grpc_completion_queue_destroy(cc=%p)", 1, (cc));
   GPR_TIMER_BEGIN("grpc_completion_queue_destroy", 0);
   grpc_completion_queue_shutdown(cc);
+
+  /* TODO (sreek): This should not ideally be here. Refactor it into the
+   * cq_vtable (perhaps have a create/destroy methods in the cq vtable) */
+  if (cc->vtable->cq_completion_type == GRPC_CQ_NEXT) {
+    GPR_ASSERT(cq_event_queue_num_items(&cc->data.queue) == 0);
+  }
+
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GRPC_CQ_INTERNAL_UNREF(&exec_ctx, cc, "destroy");
   grpc_exec_ctx_finish(&exec_ctx);
@@ -835,22 +1126,12 @@
   return CQ_FROM_POLLSET(ps);
 }
 
-void grpc_cq_mark_non_listening_server_cq(grpc_completion_queue *cc) {
-  /* TODO: sreek - use cc->polling_type field here and add a validation check
-     (i.e grpc_cq_mark_non_listening_server_cq can only be called on a cc whose
-     polling_type is set to GRPC_CQ_NON_LISTENING */
-  cc->is_non_listening_server_cq = 1;
+void grpc_cq_mark_server_cq(grpc_completion_queue *cc) {
+  cc->data.is_server_cq = 1;
 }
 
-bool grpc_cq_is_non_listening_server_cq(grpc_completion_queue *cc) {
-  /* TODO (sreek) - return (cc->polling_type == GRPC_CQ_NON_LISTENING) */
-  return (cc->is_non_listening_server_cq == 1);
-}
-
-void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; }
-
 bool grpc_cq_is_server_cq(grpc_completion_queue *cc) {
-  return cc->is_server_cq;
+  return cc->data.is_server_cq;
 }
 
 bool grpc_cq_can_listen(grpc_completion_queue *cc) {
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index 8d9ce2e..7963ea7 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -49,7 +49,13 @@
 extern grpc_tracer_flag grpc_trace_pending_tags;
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct grpc_cq_completion {
+  gpr_mpscq_node node;
+
   /** user supplied tag */
   void *tag;
   /** done callback - called when this queue element is no longer
@@ -101,7 +107,13 @@
 
 grpc_cq_completion_type grpc_get_cq_completion_type(grpc_completion_queue *cc);
 
+int grpc_get_cq_poll_num(grpc_completion_queue *cc);
+
 grpc_completion_queue *grpc_completion_queue_create_internal(
     grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 560229e..7e4ae42 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -47,7 +47,8 @@
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/slice/slice_internal.h"
-#include "src/core/lib/support/stack_lockfree.h"
+#include "src/core/lib/support/mpscq.h"
+#include "src/core/lib/support/spinlock.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/call.h"
@@ -76,6 +77,7 @@
 grpc_tracer_flag grpc_server_channel_trace = GRPC_TRACER_INITIALIZER(false);
 
 typedef struct requested_call {
+  gpr_mpscq_node request_link; /* must be first */
   requested_call_type type;
   size_t cq_idx;
   void *tag;
@@ -175,7 +177,7 @@
   grpc_server *server;
   call_data *pending_head;
   call_data *pending_tail;
-  gpr_stack_lockfree **requests_per_cq;
+  gpr_locked_mpscq *requests_per_cq;
 };
 
 struct registered_method {
@@ -220,11 +222,6 @@
   registered_method *registered_methods;
   /** one request matcher for unregistered methods */
   request_matcher unregistered_request_matcher;
-  /** free list of available requested_calls_per_cq indices */
-  gpr_stack_lockfree **request_freelist_per_cq;
-  /** requested call backing data */
-  requested_call **requested_calls_per_cq;
-  int max_requested_calls_per_cq;
 
   gpr_atm shutdown_flag;
   uint8_t shutdown_published;
@@ -324,21 +321,20 @@
  * request_matcher
  */
 
-static void request_matcher_init(request_matcher *rm, size_t entries,
-                                 grpc_server *server) {
+static void request_matcher_init(request_matcher *rm, grpc_server *server) {
   memset(rm, 0, sizeof(*rm));
   rm->server = server;
   rm->requests_per_cq =
       gpr_malloc(sizeof(*rm->requests_per_cq) * server->cq_count);
   for (size_t i = 0; i < server->cq_count; i++) {
-    rm->requests_per_cq[i] = gpr_stack_lockfree_create(entries);
+    gpr_locked_mpscq_init(&rm->requests_per_cq[i]);
   }
 }
 
 static void request_matcher_destroy(request_matcher *rm) {
   for (size_t i = 0; i < rm->server->cq_count; i++) {
-    GPR_ASSERT(gpr_stack_lockfree_pop(rm->requests_per_cq[i]) == -1);
-    gpr_stack_lockfree_destroy(rm->requests_per_cq[i]);
+    GPR_ASSERT(gpr_locked_mpscq_pop(&rm->requests_per_cq[i]) == NULL);
+    gpr_locked_mpscq_destroy(&rm->requests_per_cq[i]);
   }
   gpr_free(rm->requests_per_cq);
 }
@@ -368,13 +364,17 @@
                                           grpc_server *server,
                                           request_matcher *rm,
                                           grpc_error *error) {
-  int request_id;
+  requested_call *rc;
   for (size_t i = 0; i < server->cq_count; i++) {
-    while ((request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[i])) !=
-           -1) {
-      fail_call(exec_ctx, server, i,
-                &server->requested_calls_per_cq[i][request_id],
-                GRPC_ERROR_REF(error));
+    /* Here we know:
+       1. no requests are being added (since the server is shut down)
+       2. no other threads are pulling (since the shut down process is single
+          threaded)
+       So, we can ignore the queue lock and just pop, with the guarantee that a
+       NULL returned here truly means that the queue is empty */
+    while ((rc = (requested_call *)gpr_mpscq_pop(
+                &rm->requests_per_cq[i].queue)) != NULL) {
+      fail_call(exec_ctx, server, i, rc, GRPC_ERROR_REF(error));
     }
   }
   GRPC_ERROR_UNREF(error);
@@ -409,13 +409,7 @@
   }
   for (i = 0; i < server->cq_count; i++) {
     GRPC_CQ_INTERNAL_UNREF(exec_ctx, server->cqs[i], "server");
-    if (server->started) {
-      gpr_stack_lockfree_destroy(server->request_freelist_per_cq[i]);
-      gpr_free(server->requested_calls_per_cq[i]);
-    }
   }
-  gpr_free(server->request_freelist_per_cq);
-  gpr_free(server->requested_calls_per_cq);
   gpr_free(server->cqs);
   gpr_free(server->pollsets);
   gpr_free(server->shutdown_tags);
@@ -473,21 +467,7 @@
 
 static void done_request_event(grpc_exec_ctx *exec_ctx, void *req,
                                grpc_cq_completion *c) {
-  requested_call *rc = req;
-  grpc_server *server = rc->server;
-
-  if (rc >= server->requested_calls_per_cq[rc->cq_idx] &&
-      rc < server->requested_calls_per_cq[rc->cq_idx] +
-               server->max_requested_calls_per_cq) {
-    GPR_ASSERT(rc - server->requested_calls_per_cq[rc->cq_idx] <= INT_MAX);
-    gpr_stack_lockfree_push(
-        server->request_freelist_per_cq[rc->cq_idx],
-        (int)(rc - server->requested_calls_per_cq[rc->cq_idx]));
-  } else {
-    gpr_free(req);
-  }
-
-  server_unref(exec_ctx, server);
+  gpr_free(req);
 }
 
 static void publish_call(grpc_exec_ctx *exec_ctx, grpc_server *server,
@@ -516,10 +496,6 @@
       GPR_UNREACHABLE_CODE(return );
   }
 
-  grpc_call_element *elem =
-      grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
-  channel_data *chand = elem->channel_data;
-  server_ref(chand->server);
   grpc_cq_end_op(exec_ctx, calld->cq_new, rc->tag, GRPC_ERROR_NONE,
                  done_request_event, rc, &rc->completion);
 }
@@ -547,15 +523,15 @@
 
   for (size_t i = 0; i < server->cq_count; i++) {
     size_t cq_idx = (chand->cq_idx + i) % server->cq_count;
-    int request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[cq_idx]);
-    if (request_id == -1) {
+    requested_call *rc =
+        (requested_call *)gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]);
+    if (rc == NULL) {
       continue;
     } else {
       gpr_mu_lock(&calld->mu_state);
       calld->state = ACTIVATED;
       gpr_mu_unlock(&calld->mu_state);
-      publish_call(exec_ctx, server, calld, cq_idx,
-                   &server->requested_calls_per_cq[cq_idx][request_id]);
+      publish_call(exec_ctx, server, calld, cq_idx, rc);
       return; /* early out */
     }
   }
@@ -1029,8 +1005,6 @@
   server->root_channel_data.next = server->root_channel_data.prev =
       &server->root_channel_data;
 
-  /* TODO(ctiller): expose a channel_arg for this */
-  server->max_requested_calls_per_cq = 32768;
   server->channel_args = grpc_channel_args_copy(args);
 
   return server;
@@ -1103,29 +1077,15 @@
   server->started = true;
   server->pollset_count = 0;
   server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
-  server->request_freelist_per_cq =
-      gpr_malloc(sizeof(*server->request_freelist_per_cq) * server->cq_count);
-  server->requested_calls_per_cq =
-      gpr_malloc(sizeof(*server->requested_calls_per_cq) * server->cq_count);
   for (i = 0; i < server->cq_count; i++) {
     if (grpc_cq_can_listen(server->cqs[i])) {
       server->pollsets[server->pollset_count++] =
           grpc_cq_pollset(server->cqs[i]);
     }
-    server->request_freelist_per_cq[i] =
-        gpr_stack_lockfree_create((size_t)server->max_requested_calls_per_cq);
-    for (int j = 0; j < server->max_requested_calls_per_cq; j++) {
-      gpr_stack_lockfree_push(server->request_freelist_per_cq[i], j);
-    }
-    server->requested_calls_per_cq[i] =
-        gpr_malloc((size_t)server->max_requested_calls_per_cq *
-                   sizeof(*server->requested_calls_per_cq[i]));
   }
-  request_matcher_init(&server->unregistered_request_matcher,
-                       (size_t)server->max_requested_calls_per_cq, server);
+  request_matcher_init(&server->unregistered_request_matcher, server);
   for (registered_method *rm = server->registered_methods; rm; rm = rm->next) {
-    request_matcher_init(&rm->request_matcher,
-                         (size_t)server->max_requested_calls_per_cq, server);
+    request_matcher_init(&rm->request_matcher, server);
   }
 
   server_ref(server);
@@ -1379,21 +1339,11 @@
                                           requested_call *rc) {
   call_data *calld = NULL;
   request_matcher *rm = NULL;
-  int request_id;
   if (gpr_atm_acq_load(&server->shutdown_flag)) {
     fail_call(exec_ctx, server, cq_idx, rc,
               GRPC_ERROR_CREATE_FROM_STATIC_STRING("Server Shutdown"));
     return GRPC_CALL_OK;
   }
-  request_id = gpr_stack_lockfree_pop(server->request_freelist_per_cq[cq_idx]);
-  if (request_id == -1) {
-    /* out of request ids: just fail this one */
-    fail_call(exec_ctx, server, cq_idx, rc,
-              grpc_error_set_int(
-                  GRPC_ERROR_CREATE_FROM_STATIC_STRING("Out of request ids"),
-                  GRPC_ERROR_INT_LIMIT, server->max_requested_calls_per_cq));
-    return GRPC_CALL_OK;
-  }
   switch (rc->type) {
     case BATCH_CALL:
       rm = &server->unregistered_request_matcher;
@@ -1402,15 +1352,13 @@
       rm = &rc->data.registered.registered_method->request_matcher;
       break;
   }
-  server->requested_calls_per_cq[cq_idx][request_id] = *rc;
-  gpr_free(rc);
-  if (gpr_stack_lockfree_push(rm->requests_per_cq[cq_idx], request_id)) {
+  if (gpr_locked_mpscq_push(&rm->requests_per_cq[cq_idx], &rc->request_link)) {
     /* this was the first queued request: we need to lock and start
        matching calls */
     gpr_mu_lock(&server->mu_call);
     while ((calld = rm->pending_head) != NULL) {
-      request_id = gpr_stack_lockfree_pop(rm->requests_per_cq[cq_idx]);
-      if (request_id == -1) break;
+      rc = (requested_call *)gpr_locked_mpscq_pop(&rm->requests_per_cq[cq_idx]);
+      if (rc == NULL) break;
       rm->pending_head = calld->pending_next;
       gpr_mu_unlock(&server->mu_call);
       gpr_mu_lock(&calld->mu_state);
@@ -1426,8 +1374,7 @@
         GPR_ASSERT(calld->state == PENDING);
         calld->state = ACTIVATED;
         gpr_mu_unlock(&calld->mu_state);
-        publish_call(exec_ctx, server, calld, cq_idx,
-                     &server->requested_calls_per_cq[cq_idx][request_id]);
+        publish_call(exec_ctx, server, calld, cq_idx, rc);
       }
       gpr_mu_lock(&server->mu_call);
     }
@@ -1534,7 +1481,6 @@
   rc->initial_metadata->count = 0;
   GPR_ASSERT(error != GRPC_ERROR_NONE);
 
-  server_ref(server);
   grpc_cq_end_op(exec_ctx, server->cqs[cq_idx], rc->tag, error,
                  done_request_event, rc, &rc->completion);
 }
diff --git a/src/core/plugin_registry/grpc_plugin_registry.c b/src/core/plugin_registry/grpc_plugin_registry.c
index 25bda7a..510cf5d 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_plugin_registry.c
@@ -61,6 +61,8 @@
 extern void grpc_max_age_filter_shutdown(void);
 extern void grpc_message_size_filter_init(void);
 extern void grpc_message_size_filter_shutdown(void);
+extern void grpc_workaround_cronet_compression_filter_init(void);
+extern void grpc_workaround_cronet_compression_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_http_filters_init,
@@ -91,4 +93,6 @@
                        grpc_max_age_filter_shutdown);
   grpc_register_plugin(grpc_message_size_filter_init,
                        grpc_message_size_filter_shutdown);
+  grpc_register_plugin(grpc_workaround_cronet_compression_filter_init,
+                       grpc_workaround_cronet_compression_filter_shutdown);
 }
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
index 05d4771..e5eb68f 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
@@ -61,6 +61,8 @@
 extern void grpc_max_age_filter_shutdown(void);
 extern void grpc_message_size_filter_init(void);
 extern void grpc_message_size_filter_shutdown(void);
+extern void grpc_workaround_cronet_compression_filter_init(void);
+extern void grpc_workaround_cronet_compression_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_http_filters_init,
@@ -91,4 +93,6 @@
                        grpc_max_age_filter_shutdown);
   grpc_register_plugin(grpc_message_size_filter_init,
                        grpc_message_size_filter_shutdown);
+  grpc_register_plugin(grpc_workaround_cronet_compression_filter_init,
+                       grpc_workaround_cronet_compression_filter_shutdown);
 }
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 2f89aa3..7c93bb8 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -686,6 +686,7 @@
         StringFromCopiedSlice(call_details_.method);
     static_cast<GenericServerContext*>(context_)->host_ =
         StringFromCopiedSlice(call_details_.host);
+    context_->deadline_ = call_details_.deadline;
   }
   grpc_slice_unref(call_details_.method);
   grpc_slice_unref(call_details_.host);
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 7e0f3f0..c086500 100755
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -19,27 +19,27 @@
 
   <ItemGroup>
     <EmbeddedResource Include="..\..\..\etc\roots.pem" />
-    <Content Include="..\nativelibs\macosx_x64\libgrpc_csharp_ext.dylib">
+    <Content Include="..\nativelibs\csharp_ext_macos_x64\libgrpc_csharp_ext.dylib">
       <PackagePath>runtimes/osx/native/libgrpc_csharp_ext.x64.dylib</PackagePath>
       <Pack>true</Pack>
     </Content>
-    <Content Include="..\nativelibs\macosx_x86\libgrpc_csharp_ext.dylib">
+    <Content Include="..\nativelibs\csharp_ext_macos_x86\libgrpc_csharp_ext.dylib">
       <PackagePath>runtimes/osx/native/libgrpc_csharp_ext.x86.dylib</PackagePath>
       <Pack>true</Pack>
     </Content>
-    <Content Include="..\nativelibs\linux_x64\libgrpc_csharp_ext.so">
+    <Content Include="..\nativelibs\csharp_ext_linux_x64\libgrpc_csharp_ext.so">
       <PackagePath>runtimes/linux/native/libgrpc_csharp_ext.x64.so</PackagePath>
       <Pack>true</Pack>
     </Content>
-    <Content Include="..\nativelibs\linux_x86\libgrpc_csharp_ext.so">
+    <Content Include="..\nativelibs\csharp_ext_linux_x86\libgrpc_csharp_ext.so">
       <PackagePath>runtimes/linux/native/libgrpc_csharp_ext.x86.so</PackagePath>
       <Pack>true</Pack>
     </Content>
-    <Content Include="..\nativelibs\windows_x64\grpc_csharp_ext.dll">
+    <Content Include="..\nativelibs\csharp_ext_windows_x64\grpc_csharp_ext.dll">
       <PackagePath>runtimes/win/native/grpc_csharp_ext.x64.dll</PackagePath>
       <Pack>true</Pack>
     </Content>
-    <Content Include="..\nativelibs\windows_x86\grpc_csharp_ext.dll">
+    <Content Include="..\nativelibs\csharp_ext_windows_x86\grpc_csharp_ext.dll">
       <PackagePath>runtimes/win/native/grpc_csharp_ext.x86.dll</PackagePath>
       <Pack>true</Pack>
     </Content>
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 6af2af1..8388bfd 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -2,6 +2,6 @@
 <Project>
   <PropertyGroup>
     <GrpcCsharpVersion>1.4.0-dev</GrpcCsharpVersion>
-    <GoogleProtobufVersion>3.2.0</GoogleProtobufVersion>
+    <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
index ba4e1d6..0cae5572 100644
--- a/src/csharp/Grpc.Tools.nuspec
+++ b/src/csharp/Grpc.Tools.nuspec
@@ -17,17 +17,17 @@
   </metadata>
   <files>
     <!-- forward slashes in src path enable building on Linux -->
-    <file src="protoc_plugins/windows_x86/protoc.exe" target="tools/windows_x86/protoc.exe" />
-    <file src="protoc_plugins/windows_x86/grpc_csharp_plugin.exe" target="tools/windows_x86/grpc_csharp_plugin.exe" />
-    <file src="protoc_plugins/windows_x64/protoc.exe" target="tools/windows_x64/protoc.exe" />
-    <file src="protoc_plugins/windows_x64/grpc_csharp_plugin.exe" target="tools/windows_x64/grpc_csharp_plugin.exe" />
-    <file src="protoc_plugins/linux_x86/protoc" target="tools/linux_x86/protoc" />
-    <file src="protoc_plugins/linux_x86/grpc_csharp_plugin" target="tools/linux_x86/grpc_csharp_plugin" />
-    <file src="protoc_plugins/linux_x64/protoc" target="tools/linux_x64/protoc" />
-    <file src="protoc_plugins/linux_x64/grpc_csharp_plugin" target="tools/linux_x64/grpc_csharp_plugin" />
-    <file src="protoc_plugins/macosx_x86/protoc" target="tools/macosx_x86/protoc" />
-    <file src="protoc_plugins/macosx_x86/grpc_csharp_plugin" target="tools/macosx_x86/grpc_csharp_plugin" />
-    <file src="protoc_plugins/macosx_x64/protoc" target="tools/macosx_x64/protoc" />
-    <file src="protoc_plugins/macosx_x64/grpc_csharp_plugin" target="tools/macosx_x64/grpc_csharp_plugin" />
+    <file src="protoc_plugins/protoc_windows_x86/protoc.exe" target="tools/windows_x86/protoc.exe" />
+    <file src="protoc_plugins/protoc_windows_x86/grpc_csharp_plugin.exe" target="tools/windows_x86/grpc_csharp_plugin.exe" />
+    <file src="protoc_plugins/protoc_windows_x64/protoc.exe" target="tools/windows_x64/protoc.exe" />
+    <file src="protoc_plugins/protoc_windows_x64/grpc_csharp_plugin.exe" target="tools/windows_x64/grpc_csharp_plugin.exe" />
+    <file src="protoc_plugins/protoc_linux_x86/protoc" target="tools/linux_x86/protoc" />
+    <file src="protoc_plugins/protoc_linux_x86/grpc_csharp_plugin" target="tools/linux_x86/grpc_csharp_plugin" />
+    <file src="protoc_plugins/protoc_linux_x64/protoc" target="tools/linux_x64/protoc" />
+    <file src="protoc_plugins/protoc_linux_x64/grpc_csharp_plugin" target="tools/linux_x64/grpc_csharp_plugin" />
+    <file src="protoc_plugins/protoc_macos_x86/protoc" target="tools/macosx_x86/protoc" />
+    <file src="protoc_plugins/protoc_macos_x86/grpc_csharp_plugin" target="tools/macosx_x86/grpc_csharp_plugin" />
+    <file src="protoc_plugins/protoc_macos_x64/protoc" target="tools/macosx_x64/protoc" />
+    <file src="protoc_plugins/protoc_macos_x64/grpc_csharp_plugin" target="tools/macosx_x64/grpc_csharp_plugin" />
   </files>
 </package>
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 673642e..aa8a8d3 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -36,29 +36,20 @@
 
 set -ex
 
-mkdir -p ..\..\artifacts\
+mkdir ..\..\artifacts
 
 @rem Collect the artifacts built by the previous build step if running on Jenkins
-@rem TODO(jtattermusch): is there a better way to do this?
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* nativelibs\windows_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* nativelibs\windows_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* nativelibs\linux_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* nativelibs\linux_x64\
-xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x86\
-xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x64\
+mkdir nativelibs
+powershell -Command "cp -r ..\..\platform=*\artifacts\csharp_ext_* nativelibs"
 
 @rem Collect protoc artifacts built by the previous build step
-xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
-xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x64\
-xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x86\
-xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x64\
-xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86\
-xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64\
+mkdir protoc_plugins
+powershell -Command "cp -r ..\..\platform=*\artifacts\protoc_* protoc_plugins"
 
 %DOTNET% restore Grpc.sln || goto :error
 
 @rem To be able to build, we also need to put grpc_csharp_ext to its normal location
-xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release\
+xcopy /Y /I nativelibs\csharp_ext_windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release\
 
 %DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error
 %DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index ee923e3..d339238 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -34,35 +34,19 @@
 
 mkdir -p ../../artifacts/
 
-mkdir -p nativelibs/windows_x86 nativelibs/windows_x64 \
-    nativelibs/linux_x86 nativelibs/linux_x64 \
-    nativelibs/macosx_x86 nativelibs/macosx_x64
-
-mkdir -p protoc_plugins/windows_x86 protoc_plugins/windows_x64 \
-    protoc_plugins/linux_x86 protoc_plugins/linux_x64 \
-    protoc_plugins/macosx_x86 protoc_plugins/macosx_x64
-
-# Collect the artifacts built by the previous build step if running on Jenkins
-cp $EXTERNAL_GIT_ROOT/architecture=x86,language=csharp,platform=windows/artifacts/* nativelibs/windows_x86 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x64,language=csharp,platform=windows/artifacts/* nativelibs/windows_x64 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x86,language=csharp,platform=linux/artifacts/* nativelibs/linux_x86 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x64,language=csharp,platform=linux/artifacts/* nativelibs/linux_x64 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x86,language=csharp,platform=macos/artifacts/* nativelibs/macosx_x86 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x64,language=csharp,platform=macos/artifacts/* nativelibs/macosx_x64 || true
+# Collect the artifacts built by the previous build step
+mkdir -p nativelibs
+cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/csharp_ext_* nativelibs || true
 
 # Collect protoc artifacts built by the previous build step
-cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=windows/artifacts/* protoc_plugins/windows_x86 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=windows/artifacts/* protoc_plugins/windows_x64 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=linux/artifacts/* protoc_plugins/linux_x86 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=linux/artifacts/* protoc_plugins/linux_x64 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x86 || true
-cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x64 || true
+mkdir -p protoc_plugins
+cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/protoc_* protoc_plugins || true
 
 dotnet restore Grpc.sln
 
 # To be able to build, we also need to put grpc_csharp_ext to its normal location
 mkdir -p ../../libs/opt
-cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt
+cp nativelibs/csharp_ext_linux_x64/libgrpc_csharp_ext.so ../../libs/opt
 
 dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
 dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index e193e82..c444ad0 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -85,98 +85,6 @@
 
 static char *pem_root_certs = NULL;
 
-void InitStatusConstants(Local<Object> exports) {
-  Nan::HandleScope scope;
-  Local<Object> status = Nan::New<Object>();
-  Nan::Set(exports, Nan::New("status").ToLocalChecked(), status);
-  Local<Value> OK(Nan::New<Uint32, uint32_t>(GRPC_STATUS_OK));
-  Nan::Set(status, Nan::New("OK").ToLocalChecked(), OK);
-  Local<Value> CANCELLED(Nan::New<Uint32, uint32_t>(GRPC_STATUS_CANCELLED));
-  Nan::Set(status, Nan::New("CANCELLED").ToLocalChecked(), CANCELLED);
-  Local<Value> UNKNOWN(Nan::New<Uint32, uint32_t>(GRPC_STATUS_UNKNOWN));
-  Nan::Set(status, Nan::New("UNKNOWN").ToLocalChecked(), UNKNOWN);
-  Local<Value> INVALID_ARGUMENT(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_INVALID_ARGUMENT));
-  Nan::Set(status, Nan::New("INVALID_ARGUMENT").ToLocalChecked(),
-           INVALID_ARGUMENT);
-  Local<Value> DEADLINE_EXCEEDED(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_DEADLINE_EXCEEDED));
-  Nan::Set(status, Nan::New("DEADLINE_EXCEEDED").ToLocalChecked(),
-           DEADLINE_EXCEEDED);
-  Local<Value> NOT_FOUND(Nan::New<Uint32, uint32_t>(GRPC_STATUS_NOT_FOUND));
-  Nan::Set(status, Nan::New("NOT_FOUND").ToLocalChecked(), NOT_FOUND);
-  Local<Value> ALREADY_EXISTS(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_ALREADY_EXISTS));
-  Nan::Set(status, Nan::New("ALREADY_EXISTS").ToLocalChecked(), ALREADY_EXISTS);
-  Local<Value> PERMISSION_DENIED(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_PERMISSION_DENIED));
-  Nan::Set(status, Nan::New("PERMISSION_DENIED").ToLocalChecked(),
-           PERMISSION_DENIED);
-  Local<Value> UNAUTHENTICATED(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_UNAUTHENTICATED));
-  Nan::Set(status, Nan::New("UNAUTHENTICATED").ToLocalChecked(),
-           UNAUTHENTICATED);
-  Local<Value> RESOURCE_EXHAUSTED(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_RESOURCE_EXHAUSTED));
-  Nan::Set(status, Nan::New("RESOURCE_EXHAUSTED").ToLocalChecked(),
-           RESOURCE_EXHAUSTED);
-  Local<Value> FAILED_PRECONDITION(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_FAILED_PRECONDITION));
-  Nan::Set(status, Nan::New("FAILED_PRECONDITION").ToLocalChecked(),
-           FAILED_PRECONDITION);
-  Local<Value> ABORTED(Nan::New<Uint32, uint32_t>(GRPC_STATUS_ABORTED));
-  Nan::Set(status, Nan::New("ABORTED").ToLocalChecked(), ABORTED);
-  Local<Value> OUT_OF_RANGE(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_OUT_OF_RANGE));
-  Nan::Set(status, Nan::New("OUT_OF_RANGE").ToLocalChecked(), OUT_OF_RANGE);
-  Local<Value> UNIMPLEMENTED(
-      Nan::New<Uint32, uint32_t>(GRPC_STATUS_UNIMPLEMENTED));
-  Nan::Set(status, Nan::New("UNIMPLEMENTED").ToLocalChecked(), UNIMPLEMENTED);
-  Local<Value> INTERNAL(Nan::New<Uint32, uint32_t>(GRPC_STATUS_INTERNAL));
-  Nan::Set(status, Nan::New("INTERNAL").ToLocalChecked(), INTERNAL);
-  Local<Value> UNAVAILABLE(Nan::New<Uint32, uint32_t>(GRPC_STATUS_UNAVAILABLE));
-  Nan::Set(status, Nan::New("UNAVAILABLE").ToLocalChecked(), UNAVAILABLE);
-  Local<Value> DATA_LOSS(Nan::New<Uint32, uint32_t>(GRPC_STATUS_DATA_LOSS));
-  Nan::Set(status, Nan::New("DATA_LOSS").ToLocalChecked(), DATA_LOSS);
-}
-
-void InitCallErrorConstants(Local<Object> exports) {
-  Nan::HandleScope scope;
-  Local<Object> call_error = Nan::New<Object>();
-  Nan::Set(exports, Nan::New("callError").ToLocalChecked(), call_error);
-  Local<Value> OK(Nan::New<Uint32, uint32_t>(GRPC_CALL_OK));
-  Nan::Set(call_error, Nan::New("OK").ToLocalChecked(), OK);
-  Local<Value> CALL_ERROR(Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR));
-  Nan::Set(call_error, Nan::New("ERROR").ToLocalChecked(), CALL_ERROR);
-  Local<Value> NOT_ON_SERVER(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_SERVER));
-  Nan::Set(call_error, Nan::New("NOT_ON_SERVER").ToLocalChecked(),
-           NOT_ON_SERVER);
-  Local<Value> NOT_ON_CLIENT(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_CLIENT));
-  Nan::Set(call_error, Nan::New("NOT_ON_CLIENT").ToLocalChecked(),
-           NOT_ON_CLIENT);
-  Local<Value> ALREADY_INVOKED(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_ALREADY_INVOKED));
-  Nan::Set(call_error, Nan::New("ALREADY_INVOKED").ToLocalChecked(),
-           ALREADY_INVOKED);
-  Local<Value> NOT_INVOKED(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_INVOKED));
-  Nan::Set(call_error, Nan::New("NOT_INVOKED").ToLocalChecked(), NOT_INVOKED);
-  Local<Value> ALREADY_FINISHED(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_ALREADY_FINISHED));
-  Nan::Set(call_error, Nan::New("ALREADY_FINISHED").ToLocalChecked(),
-           ALREADY_FINISHED);
-  Local<Value> TOO_MANY_OPERATIONS(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
-  Nan::Set(call_error, Nan::New("TOO_MANY_OPERATIONS").ToLocalChecked(),
-           TOO_MANY_OPERATIONS);
-  Local<Value> INVALID_FLAGS(
-      Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_INVALID_FLAGS));
-  Nan::Set(call_error, Nan::New("INVALID_FLAGS").ToLocalChecked(),
-           INVALID_FLAGS);
-}
-
 void InitOpTypeConstants(Local<Object> exports) {
   Nan::HandleScope scope;
   Local<Object> op_type = Nan::New<Object>();
@@ -211,27 +119,6 @@
            RECV_CLOSE_ON_SERVER);
 }
 
-void InitPropagateConstants(Local<Object> exports) {
-  Nan::HandleScope scope;
-  Local<Object> propagate = Nan::New<Object>();
-  Nan::Set(exports, Nan::New("propagate").ToLocalChecked(), propagate);
-  Local<Value> DEADLINE(Nan::New<Uint32, uint32_t>(GRPC_PROPAGATE_DEADLINE));
-  Nan::Set(propagate, Nan::New("DEADLINE").ToLocalChecked(), DEADLINE);
-  Local<Value> CENSUS_STATS_CONTEXT(
-      Nan::New<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_STATS_CONTEXT));
-  Nan::Set(propagate, Nan::New("CENSUS_STATS_CONTEXT").ToLocalChecked(),
-           CENSUS_STATS_CONTEXT);
-  Local<Value> CENSUS_TRACING_CONTEXT(
-      Nan::New<Uint32, uint32_t>(GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT));
-  Nan::Set(propagate, Nan::New("CENSUS_TRACING_CONTEXT").ToLocalChecked(),
-           CENSUS_TRACING_CONTEXT);
-  Local<Value> CANCELLATION(
-      Nan::New<Uint32, uint32_t>(GRPC_PROPAGATE_CANCELLATION));
-  Nan::Set(propagate, Nan::New("CANCELLATION").ToLocalChecked(), CANCELLATION);
-  Local<Value> DEFAULTS(Nan::New<Uint32, uint32_t>(GRPC_PROPAGATE_DEFAULTS));
-  Nan::Set(propagate, Nan::New("DEFAULTS").ToLocalChecked(), DEFAULTS);
-}
-
 void InitConnectivityStateConstants(Local<Object> exports) {
   Nan::HandleScope scope;
   Local<Object> channel_state = Nan::New<Object>();
@@ -252,28 +139,6 @@
            FATAL_FAILURE);
 }
 
-void InitWriteFlags(Local<Object> exports) {
-  Nan::HandleScope scope;
-  Local<Object> write_flags = Nan::New<Object>();
-  Nan::Set(exports, Nan::New("writeFlags").ToLocalChecked(), write_flags);
-  Local<Value> BUFFER_HINT(Nan::New<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
-  Nan::Set(write_flags, Nan::New("BUFFER_HINT").ToLocalChecked(), BUFFER_HINT);
-  Local<Value> NO_COMPRESS(Nan::New<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
-  Nan::Set(write_flags, Nan::New("NO_COMPRESS").ToLocalChecked(), NO_COMPRESS);
-}
-
-void InitLogConstants(Local<Object> exports) {
-  Nan::HandleScope scope;
-  Local<Object> log_verbosity = Nan::New<Object>();
-  Nan::Set(exports, Nan::New("logVerbosity").ToLocalChecked(), log_verbosity);
-  Local<Value> LOG_DEBUG(Nan::New<Uint32, uint32_t>(GPR_LOG_SEVERITY_DEBUG));
-  Nan::Set(log_verbosity, Nan::New("DEBUG").ToLocalChecked(), LOG_DEBUG);
-  Local<Value> LOG_INFO(Nan::New<Uint32, uint32_t>(GPR_LOG_SEVERITY_INFO));
-  Nan::Set(log_verbosity, Nan::New("INFO").ToLocalChecked(), LOG_INFO);
-  Local<Value> LOG_ERROR(Nan::New<Uint32, uint32_t>(GPR_LOG_SEVERITY_ERROR));
-  Nan::Set(log_verbosity, Nan::New("ERROR").ToLocalChecked(), LOG_ERROR);
-}
-
 NAN_METHOD(MetadataKeyIsLegal) {
   if (!info[0]->IsString()) {
     return Nan::ThrowTypeError("headerKeyIsLegal's argument must be a string");
@@ -421,13 +286,8 @@
   grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
   init_logger();
 
-  InitStatusConstants(exports);
-  InitCallErrorConstants(exports);
   InitOpTypeConstants(exports);
-  InitPropagateConstants(exports);
   InitConnectivityStateConstants(exports);
-  InitWriteFlags(exports);
-  InitLogConstants(exports);
 
   grpc_pollset_work_run_loop = 0;
 
diff --git a/src/node/index.js b/src/node/index.js
index 76ab174..0da3440 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -59,6 +59,8 @@
 var protobuf_js_5_common = require('./src/protobuf_js_5_common');
 var protobuf_js_6_common = require('./src/protobuf_js_6_common');
 
+var constants = require('./src/constants.js');
+
 grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
 
 /**
@@ -212,27 +214,27 @@
 /**
  * Status name to code number mapping
  */
-exports.status = grpc.status;
+exports.status = constants.status;
 
 /**
  * Propagate flag name to number mapping
  */
-exports.propagate = grpc.propagate;
+exports.propagate = constants.propagate;
 
 /**
  * Call error name to code number mapping
  */
-exports.callError = grpc.callError;
+exports.callError = constants.callError;
 
 /**
  * Write flag name to code number mapping
  */
-exports.writeFlags = grpc.writeFlags;
+exports.writeFlags = constants.writeFlags;
 
 /**
  * Log verbosity setting name to code number mapping
  */
-exports.logVerbosity = grpc.logVerbosity;
+exports.logVerbosity = constants.logVerbosity;
 
 /**
  * Credentials factories
diff --git a/src/node/jsdoc_conf.json b/src/node/jsdoc_conf.json
index c3a0174..2d96775 100644
--- a/src/node/jsdoc_conf.json
+++ b/src/node/jsdoc_conf.json
@@ -11,7 +11,7 @@
     "package": "package.json",
     "readme": "src/node/README.md"
   },
-  "plugins": [],
+  "plugins": ["plugins/markdown"],
   "templates": {
     "cleverLinks": false,
     "monospaceLinks": false,
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 43502da..16fe06a 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -58,6 +58,8 @@
 
 var Metadata = require('./metadata');
 
+var constants = require('./constants');
+
 var EventEmitter = require('events').EventEmitter;
 
 var stream = require('stream');
@@ -127,7 +129,8 @@
        but passing an object that causes a serialization failure is a misuse
        of the API anyway, so that's OK. The primary purpose here is to give the
        programmer a useful error and to stop the stream properly */
-    this.call.cancelWithStatus(grpc.status.INTERNAL, 'Serialization failure');
+    this.call.cancelWithStatus(constants.status.INTERNAL,
+                               'Serialization failure');
     callback(e);
   }
   if (_.isFinite(encoding)) {
@@ -185,9 +188,9 @@
 function _readsDone(status) {
   /* jshint validthis: true */
   if (!status) {
-    status = {code: grpc.status.OK, details: 'OK'};
+    status = {code: constants.status.OK, details: 'OK'};
   }
-  if (status.code !== grpc.status.OK) {
+  if (status.code !== constants.status.OK) {
     this.call.cancelWithStatus(status.code, status.details);
   }
   this.finished = true;
@@ -218,12 +221,12 @@
   /* jshint validthis: true */
   var status;
   if (this.read_status && this.received_status) {
-    if (this.read_status.code !== grpc.status.OK) {
+    if (this.read_status.code !== constants.status.OK) {
       status = this.read_status;
     } else {
       status = this.received_status;
     }
-    if (status.code === grpc.status.OK) {
+    if (status.code === constants.status.OK) {
       this.push(null);
     } else {
       var error = new Error(status.details);
@@ -262,7 +265,7 @@
     try {
       deserialized = self.deserialize(data);
     } catch (e) {
-      self._readsDone({code: grpc.status.INTERNAL,
+      self._readsDone({code: constants.status.INTERNAL,
                        details: 'Failed to parse server response'});
       return;
     }
@@ -510,7 +513,7 @@
     var deserialized;
     emitter.emit('metadata', Metadata._fromCoreRepresentation(
         response.metadata));
-    if (status.code === grpc.status.OK) {
+    if (status.code === constants.status.OK) {
       if (err) {
         // Got a batch error, but OK status. Something went wrong
         args.callback(err);
@@ -522,13 +525,13 @@
           /* Change status to indicate bad server response. This will result
            * in passing an error to the callback */
           status = {
-            code: grpc.status.INTERNAL,
+            code: constants.status.INTERNAL,
             details: 'Failed to parse server response'
           };
         }
       }
     }
-    if (status.code !== grpc.status.OK) {
+    if (status.code !== constants.status.OK) {
       error = new Error(status.details);
       error.code = status.code;
       error.metadata = status.metadata;
@@ -593,7 +596,7 @@
     var status = response.status;
     var error;
     var deserialized;
-    if (status.code === grpc.status.OK) {
+    if (status.code === constants.status.OK) {
       if (err) {
         // Got a batch error, but OK status. Something went wrong
         args.callback(err);
@@ -605,13 +608,13 @@
           /* Change status to indicate bad server response. This will result
            * in passing an error to the callback */
           status = {
-            code: grpc.status.INTERNAL,
+            code: constants.status.INTERNAL,
             details: 'Failed to parse server response'
           };
         }
       }
     }
-    if (status.code !== grpc.status.OK) {
+    if (status.code !== constants.status.OK) {
       error = new Error(response.status.details);
       error.code = status.code;
       error.metadata = status.metadata;
@@ -921,7 +924,7 @@
 /**
  * Map of status code names to status codes
  */
-exports.status = grpc.status;
+exports.status = constants.status;
 
 /**
  * See docs for client.callError
diff --git a/src/node/src/constants.js b/src/node/src/constants.js
new file mode 100644
index 0000000..528dab1
--- /dev/null
+++ b/src/node/src/constants.js
@@ -0,0 +1,241 @@
+/*
+ *
+ * Copyright 2017, 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.
+ *
+ */
+
+/**
+ * @module
+ */
+
+/* The comments about status codes are copied verbatim (with some formatting
+ * modifications) from include/grpc/impl/codegen/status.h, for the purpose of
+ * including them in generated documentation.
+ */
+/**
+ * Enum of status codes that gRPC can return
+ * @readonly
+ * @enum {number}
+ */
+exports.status = {
+  /** Not an error; returned on success */
+  OK: 0,
+  /** The operation was cancelled (typically by the caller). */
+  CANCELLED: 1,
+  /**
+   * Unknown error.  An example of where this error may be returned is
+   * if a status value received from another address space belongs to
+   * an error-space that is not known in this address space.  Also
+   * errors raised by APIs that do not return enough error information
+   * may be converted to this error.
+   */
+  UNKNOWN: 2,
+  /**
+   * Client specified an invalid argument.  Note that this differs
+   * from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
+   * that are problematic regardless of the state of the system
+   * (e.g., a malformed file name).
+   */
+  INVALID_ARGUMENT: 3,
+  /**
+   * Deadline expired before operation could complete.  For operations
+   * that change the state of the system, this error may be returned
+   * even if the operation has completed successfully.  For example, a
+   * successful response from a server could have been delayed long
+   * enough for the deadline to expire.
+   */
+  DEADLINE_EXCEEDED: 4,
+  /** Some requested entity (e.g., file or directory) was not found. */
+  NOT_FOUND: 5,
+  /**
+   * Some entity that we attempted to create (e.g., file or directory)
+   * already exists.
+   */
+  ALREADY_EXISTS: 6,
+  /**
+   * The caller does not have permission to execute the specified
+   * operation.  PERMISSION_DENIED must not be used for rejections
+   * caused by exhausting some resource (use RESOURCE_EXHAUSTED
+   * instead for those errors).  PERMISSION_DENIED must not be
+   * used if the caller can not be identified (use UNAUTHENTICATED
+   * instead for those errors).
+   */
+  PERMISSION_DENIED: 7,
+  /**
+   * Some resource has been exhausted, perhaps a per-user quota, or
+   * perhaps the entire file system is out of space.
+   */
+  RESOURCE_EXHAUSTED: 8,
+  /**
+   * Operation was rejected because the system is not in a state
+   * required for the operation's execution.  For example, directory
+   * to be deleted may be non-empty, an rmdir operation is applied to
+   * a non-directory, etc.
+   *
+   * A litmus test that may help a service implementor in deciding
+   * between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+   *
+   *  - Use UNAVAILABLE if the client can retry just the failing call.
+   *  - Use ABORTED if the client should retry at a higher-level
+   *    (e.g., restarting a read-modify-write sequence).
+   *  - Use FAILED_PRECONDITION if the client should not retry until
+   *    the system state has been explicitly fixed.  E.g., if an "rmdir"
+   *    fails because the directory is non-empty, FAILED_PRECONDITION
+   *    should be returned since the client should not retry unless
+   *    they have first fixed up the directory by deleting files from it.
+   *  - Use FAILED_PRECONDITION if the client performs conditional
+   *    REST Get/Update/Delete on a resource and the resource on the
+   *    server does not match the condition. E.g., conflicting
+   *    read-modify-write on the same resource.
+   */
+  FAILED_PRECONDITION: 9,
+  /**
+   * The operation was aborted, typically due to a concurrency issue
+   * like sequencer check failures, transaction aborts, etc.
+   *
+   * See litmus test above for deciding between FAILED_PRECONDITION,
+   * ABORTED, and UNAVAILABLE.
+   */
+  ABORTED: 10,
+  /**
+   * Operation was attempted past the valid range.  E.g., seeking or
+   * reading past end of file.
+   *
+   * Unlike INVALID_ARGUMENT, this error indicates a problem that may
+   * be fixed if the system state changes. For example, a 32-bit file
+   * system will generate INVALID_ARGUMENT if asked to read at an
+   * offset that is not in the range [0,2^32-1], but it will generate
+   * OUT_OF_RANGE if asked to read from an offset past the current
+   * file size.
+   *
+   * There is a fair bit of overlap between FAILED_PRECONDITION and
+   * OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
+   * error) when it applies so that callers who are iterating through
+   * a space can easily look for an OUT_OF_RANGE error to detect when
+   * they are done.
+   */
+  OUT_OF_RANGE: 11,
+  /** Operation is not implemented or not supported/enabled in this service. */
+  UNIMPLEMENTED: 12,
+  /**
+   * Internal errors.  Means some invariants expected by underlying
+   * system has been broken.  If you see one of these errors,
+   * something is very broken.
+   */
+  INTERNAL: 13,
+  /**
+   * The service is currently unavailable.  This is a most likely a
+   * transient condition and may be corrected by retrying with
+   * a backoff.
+   *
+   * See litmus test above for deciding between FAILED_PRECONDITION,
+   * ABORTED, and UNAVAILABLE. */
+  UNAVAILABLE: 14,
+  /** Unrecoverable data loss or corruption. */
+  DATA_LOSS: 15,
+  /**
+   * The request does not have valid authentication credentials for the
+   * operation.
+   */
+  UNAUTHENTICATED: 16
+};
+
+/* The comments about propagation bit flags are copied rom
+ * include/grpc/impl/codegen/propagation_bits.h for the purpose of including
+ * them in generated documentation.
+ */
+/**
+ * Propagation flags: these can be bitwise or-ed to form the propagation option
+ * for calls.
+ *
+ * Users are encouraged to write propagation masks as deltas from the default.
+ * i.e. write `grpc.propagate.DEFAULTS & ~grpc.propagate.DEADLINE` to disable
+ * deadline propagation.
+ * @enum {number}
+ */
+exports.propagate = {
+  DEADLINE: 1,
+  CENSUS_STATS_CONTEXT: 2,
+  CENSUS_TRACING_CONTEXT: 4,
+  CANCELLATION: 8,
+  DEFAULTS: 65535
+};
+
+/* Many of the following comments are copied from
+ * include/grpc/impl/codegen/grpc_types.h
+ */
+/**
+ * Call error constants. Call errors almost always indicate bugs in the gRPC
+ * library, and these error codes are mainly useful for finding those bugs.
+ * @enum {number}
+ */
+exports.callError = {
+  OK: 0,
+  ERROR: 1,
+  NOT_ON_SERVER: 2,
+  NOT_ON_CLIENT: 3,
+  ALREADY_INVOKED: 5,
+  NOT_INVOKED: 6,
+  ALREADY_FINISHED: 7,
+  TOO_MANY_OPERATIONS: 8,
+  INVALID_FLAGS: 9,
+  INVALID_METADATA: 10,
+  INVALID_MESSAGE: 11,
+  NOT_SERVER_COMPLETION_QUEUE: 12,
+  BATCH_TOO_BIG: 13,
+  PAYLOAD_TYPE_MISMATCH: 14
+};
+
+/**
+ * Write flags: these can be bitwise or-ed to form write options that modify
+ * how data is written.
+ * @enum {number}
+ */
+exports.writeFlags = {
+  /**
+   * Hint that the write may be buffered and need not go out on the wire
+   * immediately. GRPC is free to buffer the message until the next non-buffered
+   * write, or until writes_done, but it need not buffer completely or at all.
+   */
+  BUFFER_HINT: 1,
+  /**
+   * Force compression to be disabled for a particular write
+   */
+  NO_COMPRESS: 2
+};
+
+/**
+ * @enum {number}
+ */
+exports.logVerbosity = {
+  DEBUG: 0,
+  INFO: 1,
+  ERROR: 2
+};
diff --git a/src/node/src/credentials.js b/src/node/src/credentials.js
index 51ff1da..b1e86bb 100644
--- a/src/node/src/credentials.js
+++ b/src/node/src/credentials.js
@@ -71,6 +71,8 @@
 
 var common = require('./common.js');
 
+var constants = require('./constants');
+
 var _ = require('lodash');
 
 /**
@@ -97,14 +99,14 @@
   return CallCredentials.createFromPlugin(function(service_url, cb_data,
                                                    callback) {
     metadata_generator({service_url: service_url}, function(error, metadata) {
-      var code = grpc.status.OK;
+      var code = constants.status.OK;
       var message = '';
       if (error) {
         message = error.message;
         if (error.hasOwnProperty('code') && _.isFinite(error.code)) {
           code = error.code;
         } else {
-          code = grpc.status.UNAUTHENTICATED;
+          code = constants.status.UNAUTHENTICATED;
         }
         if (!metadata) {
           metadata = new Metadata();
@@ -125,7 +127,7 @@
     var service_url = auth_context.service_url;
     google_credential.getRequestMetadata(service_url, function(err, header) {
       if (err) {
-        common.log(grpc.logVerbosity.INFO, 'Auth error:' + err);
+        common.log(constants.logVerbosity.INFO, 'Auth error:' + err);
         callback(err);
         return;
       }
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 3450abe..08417a7 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -57,6 +57,8 @@
 
 var Metadata = require('./metadata');
 
+var constants = require('./constants');
+
 var stream = require('stream');
 
 var Readable = stream.Readable;
@@ -75,7 +77,7 @@
 function handleError(call, error) {
   var statusMetadata = new Metadata();
   var status = {
-    code: grpc.status.UNKNOWN,
+    code: constants.status.UNKNOWN,
     details: 'Unknown Error'
   };
   if (error.hasOwnProperty('message')) {
@@ -115,7 +117,7 @@
   var end_batch = {};
   var statusMetadata = new Metadata();
   var status = {
-    code: grpc.status.OK,
+    code: constants.status.OK,
     details: 'OK'
   };
   if (metadata) {
@@ -125,7 +127,7 @@
   try {
     message = serialize(value);
   } catch (e) {
-    e.code = grpc.status.INTERNAL;
+    e.code = constants.status.INTERNAL;
     handleError(call, e);
     return;
   }
@@ -151,7 +153,7 @@
 function setUpWritable(stream, serialize) {
   stream.finished = false;
   stream.status = {
-    code : grpc.status.OK,
+    code : constants.status.OK,
     details : 'OK',
     metadata : new Metadata()
   };
@@ -178,7 +180,7 @@
    * @param {Error} err The error object
    */
   function setStatus(err) {
-    var code = grpc.status.UNKNOWN;
+    var code = constants.status.UNKNOWN;
     var details = 'Unknown Error';
     var metadata = new Metadata();
     if (err.hasOwnProperty('message')) {
@@ -284,7 +286,7 @@
   try {
     message = this.serialize(chunk);
   } catch (e) {
-    e.code = grpc.status.INTERNAL;
+    e.code = constants.status.INTERNAL;
     callback(e);
     return;
   }
@@ -353,7 +355,7 @@
     try {
       deserialized = self.deserialize(data);
     } catch (e) {
-      e.code = grpc.status.INTERNAL;
+      e.code = constants.status.INTERNAL;
       self.emit('error', e);
       return;
     }
@@ -489,7 +491,7 @@
     try {
       emitter.request = handler.deserialize(result.read);
     } catch (e) {
-      e.code = grpc.status.INTERNAL;
+      e.code = constants.status.INTERNAL;
       handleError(call, e);
       return;
     }
@@ -530,7 +532,7 @@
     try {
       stream.request = handler.deserialize(result.read);
     } catch (e) {
-      e.code = grpc.status.INTERNAL;
+      e.code = constants.status.INTERNAL;
       stream.emit('error', e);
       return;
     }
@@ -636,7 +638,7 @@
         batch[grpc.opType.SEND_INITIAL_METADATA] =
             (new Metadata())._getCoreRepresentation();
         batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
-          code: grpc.status.UNIMPLEMENTED,
+          code: constants.status.UNIMPLEMENTED,
           details: '',
           metadata: {}
         };
@@ -699,7 +701,7 @@
 };
 
 var unimplementedStatusResponse = {
-  code: grpc.status.UNIMPLEMENTED,
+  code: constants.status.UNIMPLEMENTED,
   details: 'The server does not implement this method'
 };
 
@@ -759,8 +761,8 @@
          written in the proto file, instead of using JavaScript function
          naming style */
       if (implementation[attrs.originalName] === undefined) {
-        common.log(grpc.logVerbosity.ERROR, 'Method handler ' + name + ' for ' +
-            attrs.path + ' expected but not provided');
+        common.log(constants.logVerbosity.ERROR, 'Method handler ' + name +
+            ' for ' + attrs.path + ' expected but not provided');
         impl = defaultHandler[method_type];
       } else {
         impl = _.bind(implementation[attrs.originalName], implementation);
@@ -790,7 +792,7 @@
   var options;
   var protobuf_js_5_common = require('./protobuf_js_5_common');
   var protobuf_js_6_common = require('./protobuf_js_6_common');
-  common.log(grpc.logVerbosity.INFO,
+  common.log(constants.logVerbosity.INFO,
              'Server#addProtoService is deprecated. Use addService instead');
   if (protobuf_js_5_common.isProbablyProtobufJs5(service)) {
     options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
index eb26860..f25268e 100644
--- a/src/node/test/call_test.js
+++ b/src/node/test/call_test.js
@@ -35,6 +35,7 @@
 
 var assert = require('assert');
 var grpc = require('../src/grpc_extension');
+var constants = require('../src/constants');
 
 /**
  * Helper function to return an absolute deadline given a relative timeout in
@@ -120,7 +121,8 @@
       var batch = {};
       batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true;
       call.startBatch(batch, function(err, response) {
-        assert.strictEqual(response.status.code, grpc.status.DEADLINE_EXCEEDED);
+        assert.strictEqual(response.status.code,
+                           constants.status.DEADLINE_EXCEEDED);
         done();
       });
     });
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
deleted file mode 100644
index 414b1ac..0000000
--- a/src/node/test/constant_test.js
+++ /dev/null
@@ -1,131 +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.
- *
- */
-
-'use strict';
-
-var assert = require('assert');
-var grpc = require('../src/grpc_extension');
-
-/**
- * List of all status names
- * @const
- * @type {Array.<string>}
- */
-var statusNames = [
-  'OK',
-  'CANCELLED',
-  'UNKNOWN',
-  'INVALID_ARGUMENT',
-  'DEADLINE_EXCEEDED',
-  'NOT_FOUND',
-  'ALREADY_EXISTS',
-  'PERMISSION_DENIED',
-  'UNAUTHENTICATED',
-  'RESOURCE_EXHAUSTED',
-  'FAILED_PRECONDITION',
-  'ABORTED',
-  'OUT_OF_RANGE',
-  'UNIMPLEMENTED',
-  'INTERNAL',
-  'UNAVAILABLE',
-  'DATA_LOSS'
-];
-
-/**
- * List of all call error names
- * @const
- * @type {Array.<string>}
- */
-var callErrorNames = [
-  'OK',
-  'ERROR',
-  'NOT_ON_SERVER',
-  'NOT_ON_CLIENT',
-  'ALREADY_INVOKED',
-  'NOT_INVOKED',
-  'ALREADY_FINISHED',
-  'TOO_MANY_OPERATIONS',
-  'INVALID_FLAGS'
-];
-
-/**
- * List of all propagate flag names
- * @const
- * @type {Array.<string>}
- */
-var propagateFlagNames = [
-  'DEADLINE',
-  'CENSUS_STATS_CONTEXT',
-  'CENSUS_TRACING_CONTEXT',
-  'CANCELLATION',
-  'DEFAULTS'
-];
-/*
- * List of all connectivity state names
- * @const
- * @type {Array.<string>}
- */
-var connectivityStateNames = [
-  'IDLE',
-  'CONNECTING',
-  'READY',
-  'TRANSIENT_FAILURE',
-  'FATAL_FAILURE'
-];
-
-describe('constants', function() {
-  it('should have all of the status constants', function() {
-    for (var i = 0; i < statusNames.length; i++) {
-      assert(grpc.status.hasOwnProperty(statusNames[i]),
-             'status missing: ' + statusNames[i]);
-    }
-  });
-  it('should have all of the call errors', function() {
-    for (var i = 0; i < callErrorNames.length; i++) {
-      assert(grpc.callError.hasOwnProperty(callErrorNames[i]),
-             'call error missing: ' + callErrorNames[i]);
-    }
-  });
-  it('should have all of the propagate flags', function() {
-    for (var i = 0; i < propagateFlagNames.length; i++) {
-      assert(grpc.propagate.hasOwnProperty(propagateFlagNames[i]),
-             'call error missing: ' + propagateFlagNames[i]);
-    }
-  });
-  it('should have all of the connectivity states', function() {
-    for (var i = 0; i < connectivityStateNames.length; i++) {
-      assert(grpc.connectivityState.hasOwnProperty(connectivityStateNames[i]),
-             'connectivity status missing: ' + connectivityStateNames[i]);
-    }
-  });
-});
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
index f127a41..af455e2 100644
--- a/src/node/test/end_to_end_test.js
+++ b/src/node/test/end_to_end_test.js
@@ -35,6 +35,7 @@
 
 var assert = require('assert');
 var grpc = require('../src/grpc_extension');
+var constants = require('../src/constants');
 
 /**
  * This is used for testing functions with multiple asynchronous calls that
@@ -90,7 +91,7 @@
         client_close: true,
         metadata: {},
         status: {
-          code: grpc.status.OK,
+          code: constants.status.OK,
           details: status_text,
           metadata: {}
         }
@@ -107,7 +108,7 @@
       server_batch[grpc.opType.SEND_INITIAL_METADATA] = {};
       server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
         metadata: {},
-        code: grpc.status.OK,
+        code: constants.status.OK,
         details: status_text
       };
       server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
@@ -141,7 +142,7 @@
         send_metadata: true,
         client_close: true,
         metadata: {server_key: ['server_value']},
-        status: {code: grpc.status.OK,
+        status: {code: constants.status.OK,
                  details: status_text,
                  metadata: {}}
       });
@@ -161,7 +162,7 @@
       };
       server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
         metadata: {},
-        code: grpc.status.OK,
+        code: constants.status.OK,
         details: status_text
       };
       server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
@@ -198,7 +199,7 @@
       assert.deepEqual(response.metadata, {});
       assert(response.send_message);
       assert.strictEqual(response.read.toString(), reply_text);
-      assert.deepEqual(response.status, {code: grpc.status.OK,
+      assert.deepEqual(response.status, {code: constants.status.OK,
                                          details: status_text,
                                          metadata: {}});
       done();
@@ -220,7 +221,7 @@
         response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text);
         response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
           metadata: {},
-          code: grpc.status.OK,
+          code: constants.status.OK,
           details: status_text
         };
         response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
@@ -260,7 +261,7 @@
           send_message: true,
           client_close: true,
           status: {
-            code: grpc.status.OK,
+            code: constants.status.OK,
             details: status_text,
             metadata: {}
           }
@@ -290,7 +291,7 @@
           end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true;
           end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = {
             metadata: {},
-            code: grpc.status.OK,
+            code: constants.status.OK,
             details: status_text
           };
           server_call.startBatch(end_batch, function(err, response) {
diff --git a/src/php/README.md b/src/php/README.md
index f9f93ba..90c8cb3 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -174,6 +174,28 @@
 ```
 
 
+### Protobuf Runtime library
+
+There are two protobuf runtime libraries to choose from. They are idenfical in terms of APIs offered.
+
+1. C implementation (for better performance)
+
+``` sh
+$ sudo pecl install protobuf
+```
+
+2. PHP implementation (for easier installation)
+
+
+Add this to your `composer.json` file:
+
+```
+  "require": {
+    "google/protobuf": "^v3.3.0"
+  }
+``` 
+
+
 ### PHP Protoc Plugin
 
 You need the gRPC PHP protoc plugin to generate the client stub classes.
diff --git a/src/php/tests/qps/composer.json b/src/php/tests/qps/composer.json
index 0fc8709..8c1e7b6 100644
--- a/src/php/tests/qps/composer.json
+++ b/src/php/tests/qps/composer.json
@@ -1,7 +1,8 @@
 {
   "minimum-stability": "dev",
   "require": {
-    "grpc/grpc": "dev-master"
+    "grpc/grpc": "dev-master",
+    "google/protobuf": "^v3.3.0"
   },
   "autoload": {
     "psr-4": {
diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD
index 805988c..5f1c005 100644
--- a/src/proto/grpc/testing/BUILD
+++ b/src/proto/grpc/testing/BUILD
@@ -42,8 +42,11 @@
 grpc_proto_library(
     name = "control_proto",
     srcs = ["control.proto"],
-    deps = ["payloads_proto", "stats_proto"],
     has_services = False,
+    deps = [
+        "payloads_proto",
+        "stats_proto",
+    ],
 )
 
 grpc_proto_library(
@@ -101,5 +104,8 @@
 grpc_proto_library(
     name = "test_proto",
     srcs = ["test.proto"],
-    deps = ["empty_proto", "messages_proto"],
+    deps = [
+        "empty_proto",
+        "messages_proto",
+    ],
 )
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index 02b156d..1f4569e 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -244,6 +244,10 @@
   // Number of requests that succeeded/failed
   double successful_requests_per_second = 13;
   double failed_requests_per_second = 14;
+
+  // Number of polls called inside completion queue per request
+  double client_polls_per_request = 15;
+  double server_polls_per_request = 16;
 }
 
 // Results of a single benchmark scenario.
diff --git a/src/proto/grpc/testing/stats.proto b/src/proto/grpc/testing/stats.proto
index 8001416..e236cf1 100644
--- a/src/proto/grpc/testing/stats.proto
+++ b/src/proto/grpc/testing/stats.proto
@@ -47,6 +47,9 @@
 
   // change in idle time of the server (data from proc/stat)
   uint64 idle_cpu_time = 5;
+
+  // Number of polls called inside completion queue
+  uint64 cq_poll_count = 6;
 }
 
 // Histogram params based on grpc/support/histogram.c
@@ -81,4 +84,7 @@
 
   // Number of failed requests (one row per status code seen)
   repeated RequestResultCount request_results = 5;
+
+  // Number of polls called inside completion queue
+  uint64 cq_poll_count = 6;
 }
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index dd2e550..9770301 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -103,6 +103,7 @@
   'src/core/lib/iomgr/ev_epollsig_linux.c',
   'src/core/lib/iomgr/ev_poll_posix.c',
   'src/core/lib/iomgr/ev_posix.c',
+  'src/core/lib/iomgr/ev_windows.c',
   'src/core/lib/iomgr/exec_ctx.c',
   'src/core/lib/iomgr/executor.c',
   'src/core/lib/iomgr/iocp_windows.c',
@@ -320,6 +321,8 @@
   'src/core/ext/census/tracing.c',
   'src/core/ext/filters/max_age/max_age_filter.c',
   'src/core/ext/filters/message_size/message_size_filter.c',
+  'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c',
+  'src/core/ext/filters/workarounds/workaround_utils.c',
   'src/core/plugin_registry/grpc_plugin_registry.c',
   'src/boringssl/err_data.c',
   'third_party/boringssl/crypto/aes/aes.c',
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index 7ee5336..658994d 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -56,7 +56,8 @@
     'grpcio>={version}'.format(version=grpc_version.VERSION),
     'grpcio-tools>={version}'.format(version=grpc_version.VERSION),
     'grpcio-health-checking>={version}'.format(version=grpc_version.VERSION),
-    'oauth2client>=1.4.7', 'protobuf>=3.3.0', 'six>=1.10',)
+    'oauth2client>=1.4.7', 'protobuf>=3.3.0', 'six>=1.10', 'google-auth>=1.0.0',
+    'requests>=2.14.2')
 
 COMMAND_CLASS = {
     # Run `preprocess` *before* doing any packaging!
diff --git a/src/python/grpcio_tests/tests/interop/client.py b/src/python/grpcio_tests/tests/interop/client.py
index 97f6843..9be3ba5 100644
--- a/src/python/grpcio_tests/tests/interop/client.py
+++ b/src/python/grpcio_tests/tests/interop/client.py
@@ -29,10 +29,11 @@
 """The Python implementation of the GRPC interoperability test client."""
 
 import argparse
-from oauth2client import client as oauth2client_client
+import os
 
+from google import auth as google_auth
+from google.auth import jwt as google_auth_jwt
 import grpc
-from grpc.beta import implementations
 from src.proto.grpc.testing import test_pb2
 
 from tests.interop import methods
@@ -84,25 +85,24 @@
 def _stub(args):
     target = '{}:{}'.format(args.server_host, args.server_port)
     if args.test_case == 'oauth2_auth_token':
-        google_credentials = _application_default_credentials()
-        scoped_credentials = google_credentials.create_scoped(
-            [args.oauth_scope])
-        access_token = scoped_credentials.get_access_token().access_token
-        call_credentials = grpc.access_token_call_credentials(access_token)
+        google_credentials, unused_project_id = google_auth.default(
+            scopes=[args.oauth_scope])
+        google_credentials.refresh(google_auth.transport.requests.Request())
+        call_credentials = grpc.access_token_call_credentials(
+            google_credentials.token)
     elif args.test_case == 'compute_engine_creds':
-        google_credentials = _application_default_credentials()
-        scoped_credentials = google_credentials.create_scoped(
-            [args.oauth_scope])
-        # TODO(https://github.com/grpc/grpc/issues/6799): Eliminate this last
-        # remaining use of the Beta API.
-        call_credentials = implementations.google_call_credentials(
-            scoped_credentials)
+        google_credentials, unused_project_id = google_auth.default(
+            scopes=[args.oauth_scope])
+        call_credentials = grpc.metadata_call_credentials(
+            google_auth.transport.grpc.AuthMetadataPlugin(
+                credentials=google_credentials,
+                request=google_auth.transport.requests.Request()))
     elif args.test_case == 'jwt_token_creds':
-        google_credentials = _application_default_credentials()
-        # TODO(https://github.com/grpc/grpc/issues/6799): Eliminate this last
-        # remaining use of the Beta API.
-        call_credentials = implementations.google_call_credentials(
-            google_credentials)
+        google_credentials = google_auth_jwt.OnDemandCredentials.from_service_account_file(
+            os.environ[google_auth.environment_vars.CREDENTIALS])
+        call_credentials = grpc.metadata_call_credentials(
+            google_auth.transport.grpc.AuthMetadataPlugin(
+                credentials=google_credentials, request=None))
     else:
         call_credentials = None
     if args.use_tls:
diff --git a/src/python/grpcio_tests/tests/interop/methods.py b/src/python/grpcio_tests/tests/interop/methods.py
index e1016f7..354b51d 100644
--- a/src/python/grpcio_tests/tests/interop/methods.py
+++ b/src/python/grpcio_tests/tests/interop/methods.py
@@ -33,8 +33,10 @@
 import os
 import threading
 
-from oauth2client import client as oauth2client_client
-
+from google import auth as google_auth
+from google.auth import environment_vars as google_auth_environment_vars
+from google.auth.transport import grpc as google_auth_transport_grpc
+from google.auth.transport import requests as google_auth_transport_requests
 import grpc
 from grpc.beta import implementations
 
@@ -401,8 +403,7 @@
 
 
 def _oauth2_auth_token(stub, args):
-    json_key_filename = os.environ[
-        oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
+    json_key_filename = os.environ[google_auth_environment_vars.CREDENTIALS]
     wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
     response = _large_unary_common_behavior(stub, True, True, None)
     if wanted_email != response.username:
@@ -414,8 +415,7 @@
 
 
 def _jwt_token_creds(stub, args):
-    json_key_filename = os.environ[
-        oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
+    json_key_filename = os.environ[google_auth_environment_vars.CREDENTIALS]
     wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
     response = _large_unary_common_behavior(stub, True, False, None)
     if wanted_email != response.username:
@@ -424,15 +424,14 @@
 
 
 def _per_rpc_creds(stub, args):
-    json_key_filename = os.environ[
-        oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS]
+    json_key_filename = os.environ[google_auth_environment_vars.CREDENTIALS]
     wanted_email = json.load(open(json_key_filename, 'rb'))['client_email']
-    credentials = oauth2client_client.GoogleCredentials.get_application_default()
-    scoped_credentials = credentials.create_scoped([args.oauth_scope])
-    # TODO(https://github.com/grpc/grpc/issues/6799): Eliminate this last
-    # remaining use of the Beta API.
-    call_credentials = implementations.google_call_credentials(
-        scoped_credentials)
+    google_credentials, unused_project_id = google_auth.default(
+        scopes=[args.oauth_scope])
+    call_credentials = grpc.metadata_call_credentials(
+        google_auth_transport_grpc.AuthMetadataPlugin(
+            credentials=google_credentials,
+            request=google_auth_transport_requests.Request()))
     response = _large_unary_common_behavior(stub, True, False, call_credentials)
     if wanted_email != response.username:
         raise ValueError('expected username %s, got %s' %
diff --git a/templates/composer.json.template b/templates/composer.json.template
index 2d4cb11..a18624d 100644
--- a/templates/composer.json.template
+++ b/templates/composer.json.template
@@ -8,12 +8,15 @@
     "homepage": "http://grpc.io",
     "license": "BSD-3-Clause",
     "require": {
-      "php": ">=5.5.0",
-      "google/protobuf": "^v3.3.0"
+      "php": ">=5.5.0"
     },
     "require-dev": {
       "google/auth": "v0.9"
     },
+    "suggest": {
+      "ext-protobuf": "For better performance, install the protobuf C extension.",
+      "google/protobuf": "To get started using grpc quickly, install the native protobuf library."
+    },
     "autoload": {
       "psr-4": {
         "Grpc\\": "src/php/lib/Grpc/"
diff --git a/templates/src/csharp/Grpc.Core/Version.csproj.include.template b/templates/src/csharp/Grpc.Core/Version.csproj.include.template
index 30b8d26..5bc66e9 100755
--- a/templates/src/csharp/Grpc.Core/Version.csproj.include.template
+++ b/templates/src/csharp/Grpc.Core/Version.csproj.include.template
@@ -4,6 +4,6 @@
   <Project>
     <PropertyGroup>
       <GrpcCsharpVersion>${settings.csharp_version}</GrpcCsharpVersion>
-      <GoogleProtobufVersion>3.2.0</GoogleProtobufVersion>
+      <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
     </PropertyGroup>
   </Project>
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 91808e0..3db1e0a 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -38,29 +38,20 @@
   
   set -ex
   
-  mkdir -p ..\..\artifacts${"\\"}
+  mkdir ..\..\artifacts
   
   @rem Collect the artifacts built by the previous build step if running on Jenkins
-  @rem TODO(jtattermusch): is there a better way to do this?
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=windows\artifacts\* nativelibs\windows_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=windows\artifacts\* nativelibs\windows_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=linux\artifacts\* nativelibs\linux_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* nativelibs\linux_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* nativelibs\macosx_x64${"\\"}
+  mkdir nativelibs
+  powershell -Command "cp -r ..\..\platform=*\artifacts\csharp_ext_* nativelibs"
   
   @rem Collect protoc artifacts built by the previous build step
-  xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x64${"\\"}
-  xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86${"\\"}
-  xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64${"\\"}
+  mkdir protoc_plugins
+  powershell -Command "cp -r ..\..\platform=*\artifacts\protoc_* protoc_plugins"
   
   %%DOTNET% restore Grpc.sln || goto :error
   
   @rem To be able to build, we also need to put grpc_csharp_ext to its normal location
-  xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release${"\\"}
+  xcopy /Y /I nativelibs\csharp_ext_windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release${"\\"}
   
   %%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error
   %%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template
index 374b236..65afec5 100755
--- a/templates/src/csharp/build_packages_dotnetcli.sh.template
+++ b/templates/src/csharp/build_packages_dotnetcli.sh.template
@@ -36,35 +36,19 @@
   
   mkdir -p ../../artifacts/
   
-  mkdir -p nativelibs/windows_x86 nativelibs/windows_x64 ${"\\"}
-      nativelibs/linux_x86 nativelibs/linux_x64 ${"\\"}
-      nativelibs/macosx_x86 nativelibs/macosx_x64
-  
-  mkdir -p protoc_plugins/windows_x86 protoc_plugins/windows_x64 ${"\\"}
-      protoc_plugins/linux_x86 protoc_plugins/linux_x64 ${"\\"}
-      protoc_plugins/macosx_x86 protoc_plugins/macosx_x64
-  
-  # Collect the artifacts built by the previous build step if running on Jenkins
-  cp $EXTERNAL_GIT_ROOT/architecture=x86,language=csharp,platform=windows/artifacts/* nativelibs/windows_x86 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x64,language=csharp,platform=windows/artifacts/* nativelibs/windows_x64 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x86,language=csharp,platform=linux/artifacts/* nativelibs/linux_x86 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x64,language=csharp,platform=linux/artifacts/* nativelibs/linux_x64 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x86,language=csharp,platform=macos/artifacts/* nativelibs/macosx_x86 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x64,language=csharp,platform=macos/artifacts/* nativelibs/macosx_x64 || true
+  # Collect the artifacts built by the previous build step
+  mkdir -p nativelibs
+  cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/csharp_ext_* nativelibs || true
   
   # Collect protoc artifacts built by the previous build step
-  cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=windows/artifacts/* protoc_plugins/windows_x86 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=windows/artifacts/* protoc_plugins/windows_x64 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=linux/artifacts/* protoc_plugins/linux_x86 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=linux/artifacts/* protoc_plugins/linux_x64 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x86 || true
-  cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x64 || true
+  mkdir -p protoc_plugins
+  cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/protoc_* protoc_plugins || true
   
   dotnet restore Grpc.sln
   
   # To be able to build, we also need to put grpc_csharp_ext to its normal location
   mkdir -p ../../libs/opt
-  cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt
+  cp nativelibs/csharp_ext_linux_x64/libgrpc_csharp_ext.so ../../libs/opt
   
   dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
   dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
diff --git a/templates/vsprojects/protoc.props.template b/templates/vsprojects/protoc.props.template
index 2c3844a..65771fc 100644
--- a/templates/vsprojects/protoc.props.template
+++ b/templates/vsprojects/protoc.props.template
@@ -5,7 +5,7 @@
   <PropertyGroup />

   <ItemDefinitionGroup>

     <ClCompile>

-      <DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings>

+      <DisableSpecificWarnings>4244;4267;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings>

     </ClCompile>

     <Link>

       <AdditionalDependencies>libprotoc.lib;%(AdditionalDependencies)</AdditionalDependencies>

diff --git a/test/core/bad_client/BUILD b/test/core/bad_client/BUILD
index 6b06955..bcfd2f1 100644
--- a/test/core/bad_client/BUILD
+++ b/test/core/bad_client/BUILD
@@ -27,6 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load(":generate_tests.bzl", "grpc_bad_client_tests")
diff --git a/test/core/bad_client/tests/large_metadata.c b/test/core/bad_client/tests/large_metadata.c
index d7a3ce9..5f3a9c9 100644
--- a/test/core/bad_client/tests/large_metadata.c
+++ b/test/core/bad_client/tests/large_metadata.c
@@ -212,12 +212,14 @@
 }
 
 int main(int argc, char **argv) {
+  int i;
+
   grpc_test_init(argc, argv);
 
   // Test sending more metadata than the server will accept.
   gpr_strvec headers;
   gpr_strvec_init(&headers);
-  for (int i = 0; i < NUM_HEADERS; ++i) {
+  for (i = 0; i < NUM_HEADERS; ++i) {
     char *str;
     gpr_asprintf(&str, "%s%02d%s",
                  PFX_TOO_MUCH_METADATA_FROM_CLIENT_HEADER_START_STR, i,
diff --git a/test/core/bad_ssl/BUILD b/test/core/bad_ssl/BUILD
index 288788a..61c634a 100644
--- a/test/core/bad_ssl/BUILD
+++ b/test/core/bad_ssl/BUILD
@@ -27,6 +27,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load(":generate_tests.bzl", "grpc_bad_ssl_tests")
diff --git a/test/core/census/BUILD b/test/core/census/BUILD
index 49680ab..3fdf511 100644
--- a/test/core/census/BUILD
+++ b/test/core/census/BUILD
@@ -27,12 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "context_test",
     srcs = ["context_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -41,10 +43,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "mlog_test",
     srcs = ["mlog_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -53,10 +55,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "resource_test",
     srcs = ["resource_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     data = [
         ":data/resource_empty_name.pb",
         ":data/resource_full.pb",
@@ -73,10 +75,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "trace_context_test",
     srcs = ["trace_context_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     data = [
         ":data/context_empty.pb",
         ":data/context_full.pb",
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD
index c659046..5e7e8c1 100644
--- a/test/core/channel/BUILD
+++ b/test/core/channel/BUILD
@@ -27,12 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "channel_args_test",
     srcs = ["channel_args_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -41,10 +43,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "channel_stack_test",
     srcs = ["channel_stack_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/client_channel/BUILD b/test/core/client_channel/BUILD
index 55a74c6..6c4b40e 100644
--- a/test/core/client_channel/BUILD
+++ b/test/core/client_channel/BUILD
@@ -27,21 +27,33 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "uri_fuzzer_test",
-  srcs = ["uri_fuzzer_test.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "uri_corpus",
-  copts = ["-std=c99"],
+    name = "uri_fuzzer_test",
+    srcs = ["uri_fuzzer_test.c"],
+    language = "C",
+    corpus = "uri_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "lb_policies_test",
     srcs = ["lb_policies_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:cq_verifier"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:cq_verifier",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/client_channel/resolvers/BUILD b/test/core/client_channel/resolvers/BUILD
index e8361cd..80ca7d3 100644
--- a/test/core/client_channel/resolvers/BUILD
+++ b/test/core/client_channel/resolvers/BUILD
@@ -27,12 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "dns_resolver_connectivity_test",
     srcs = ["dns_resolver_connectivity_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -41,10 +43,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "dns_resolver_test",
     srcs = ["dns_resolver_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -53,10 +55,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "sockaddr_resolver_test",
     srcs = ["sockaddr_resolver_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -65,10 +67,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "fake_resolver_test",
     srcs = ["fake_resolver_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/compression/BUILD b/test/core/compression/BUILD
index 9ddb4c5..bbd66bd 100644
--- a/test/core/compression/BUILD
+++ b/test/core/compression/BUILD
@@ -27,12 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "algorithm_test",
     srcs = ["algorithm_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -41,10 +43,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "compression_test",
     srcs = ["compression_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -53,10 +55,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "message_compress_test",
     srcs = ["message_compress_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/end2end/BUILD b/test/core/end2end/BUILD
index ffea1cc..cf387a9 100644
--- a/test/core/end2end/BUILD
+++ b/test/core/end2end/BUILD
@@ -27,15 +27,17 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load(":generate_tests.bzl", "grpc_end2end_tests")
 
-cc_library(
+grpc_cc_library(
     name = "cq_verifier",
     srcs = ["cq_verifier.c"],
     hdrs = ["cq_verifier.h"],
-    copts = ["-std=c99"],
+    language = "C",
     visibility = ["//test:__subpackages__"],
     deps = [
         "//:gpr",
@@ -44,7 +46,7 @@
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "ssl_test_data",
     srcs = [
         "data/client_certs.c",
@@ -53,15 +55,15 @@
         "data/test_root_cert.c",
     ],
     hdrs = ["data/ssl_test_data.h"],
-    copts = ["-std=c99"],
+    language = "C",
     visibility = ["//test:__subpackages__"],
 )
 
-cc_library(
+grpc_cc_library(
     name = "fake_resolver",
     srcs = ["fake_resolver.c"],
     hdrs = ["fake_resolver.h"],
-    copts = ["-std=c99"],
+    language = "C",
     visibility = ["//test:__subpackages__"],
     deps = [
         "//:gpr",
@@ -70,11 +72,11 @@
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "http_proxy",
     srcs = ["fixtures/http_proxy_fixture.c"],
     hdrs = ["fixtures/http_proxy_fixture.h"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -82,11 +84,11 @@
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "proxy",
     srcs = ["fixtures/proxy.c"],
     hdrs = ["fixtures/proxy.h"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index 1187e59..4f0d11c 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -145,6 +145,8 @@
 extern void streaming_error_response_pre_init(void);
 extern void trailing_metadata(grpc_end2end_test_config config);
 extern void trailing_metadata_pre_init(void);
+extern void workaround_cronet_compression(grpc_end2end_test_config config);
+extern void workaround_cronet_compression_pre_init(void);
 extern void write_buffering(grpc_end2end_test_config config);
 extern void write_buffering_pre_init(void);
 extern void write_buffering_at_end(grpc_end2end_test_config config);
@@ -204,6 +206,7 @@
   simple_request_pre_init();
   streaming_error_response_pre_init();
   trailing_metadata_pre_init();
+  workaround_cronet_compression_pre_init();
   write_buffering_pre_init();
   write_buffering_at_end_pre_init();
 }
@@ -265,6 +268,7 @@
     simple_request(config);
     streaming_error_response(config);
     trailing_metadata(config);
+    workaround_cronet_compression(config);
     write_buffering(config);
     write_buffering_at_end(config);
     return;
@@ -471,6 +475,10 @@
       trailing_metadata(config);
       continue;
     }
+    if (0 == strcmp("workaround_cronet_compression", argv[i])) {
+      workaround_cronet_compression(config);
+      continue;
+    }
     if (0 == strcmp("write_buffering", argv[i])) {
       write_buffering(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index 966031a..9123d97 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -147,6 +147,8 @@
 extern void streaming_error_response_pre_init(void);
 extern void trailing_metadata(grpc_end2end_test_config config);
 extern void trailing_metadata_pre_init(void);
+extern void workaround_cronet_compression(grpc_end2end_test_config config);
+extern void workaround_cronet_compression_pre_init(void);
 extern void write_buffering(grpc_end2end_test_config config);
 extern void write_buffering_pre_init(void);
 extern void write_buffering_at_end(grpc_end2end_test_config config);
@@ -207,6 +209,7 @@
   simple_request_pre_init();
   streaming_error_response_pre_init();
   trailing_metadata_pre_init();
+  workaround_cronet_compression_pre_init();
   write_buffering_pre_init();
   write_buffering_at_end_pre_init();
 }
@@ -269,6 +272,7 @@
     simple_request(config);
     streaming_error_response(config);
     trailing_metadata(config);
+    workaround_cronet_compression(config);
     write_buffering(config);
     write_buffering_at_end(config);
     return;
@@ -479,6 +483,10 @@
       trailing_metadata(config);
       continue;
     }
+    if (0 == strcmp("workaround_cronet_compression", argv[i])) {
+      workaround_cronet_compression(config);
+      continue;
+    }
     if (0 == strcmp("write_buffering", argv[i])) {
       write_buffering(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h
index 4d98bdd..59eab9e 100644
--- a/test/core/end2end/end2end_tests.h
+++ b/test/core/end2end/end2end_tests.h
@@ -48,6 +48,7 @@
 #define FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER 32
 #define FEATURE_MASK_DOES_NOT_SUPPORT_RESOURCE_QUOTA_SERVER 64
 #define FEATURE_MASK_DOES_NOT_SUPPORT_NETWORK_STATUS_CHANGE 128
+#define FEATURE_MASK_SUPPORTS_WORKAROUNDS 256
 
 #define FAIL_AUTH_CHECK_SERVER_ARG_NAME "fail_auth_check"
 
diff --git a/test/core/end2end/fixtures/h2_full+workarounds.c b/test/core/end2end/fixtures/h2_full+workarounds.c
new file mode 100644
index 0000000..2e9264f
--- /dev/null
+++ b/test/core/end2end/fixtures/h2_full+workarounds.c
@@ -0,0 +1,137 @@
+/*
+ *
+ * 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 "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 <grpc/support/workaround_list.h>
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
+#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h"
+#include "src/core/lib/channel/connected_channel.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 char *workarounds_arg[GRPC_MAX_WORKAROUND_ID] = {
+    GRPC_ARG_WORKAROUND_CRONET_COMPRESSION};
+
+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_for_next(NULL);
+  f.shutdown_cq = grpc_completion_queue_create_for_pluck(NULL);
+
+  return f;
+}
+
+void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *client_args) {
+  fullstack_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_fullstack(grpc_end2end_test_fixture *f,
+                                  grpc_channel_args *server_args) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  fullstack_fixture_data *ffd = f->fixture_data;
+  grpc_arg args[GRPC_MAX_WORKAROUND_ID];
+  for (uint32_t i = 0; i < GRPC_MAX_WORKAROUND_ID; i++) {
+    args[i].key = workarounds_arg[i];
+    args[i].type = GRPC_ARG_INTEGER;
+    args[i].value.integer = 1;
+  }
+  grpc_channel_args *server_args_new =
+      grpc_channel_args_copy_and_add(server_args, args, GRPC_MAX_WORKAROUND_ID);
+  if (f->server) {
+    grpc_server_destroy(f->server);
+  }
+  f->server = grpc_server_create(server_args_new, NULL);
+  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);
+  grpc_channel_args_destroy(&exec_ctx, server_args_new);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+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", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION |
+                             FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL |
+                             FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER |
+                             FEATURE_MASK_SUPPORTS_WORKAROUNDS,
+     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;
+
+  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/fuzzers/BUILD b/test/core/end2end/fuzzers/BUILD
index 4d98aa0..55810bd 100644
--- a/test/core/end2end/fuzzers/BUILD
+++ b/test/core/end2end/fuzzers/BUILD
@@ -27,30 +27,45 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "api_fuzzer",
-  srcs = ["api_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util", "//test/core/end2end:ssl_test_data"],
-  corpus = "api_fuzzer_corpus",
-  copts = ["-std=c99"],
+    name = "api_fuzzer",
+    srcs = ["api_fuzzer.c"],
+    language = "C",
+    corpus = "api_fuzzer_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_fuzzer(
-  name = "client_fuzzer",
-  srcs = ["client_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "client_fuzzer_corpus",
-  copts = ["-std=c99"],
+    name = "client_fuzzer",
+    srcs = ["client_fuzzer.c"],
+    language = "C",
+    corpus = "client_fuzzer_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_fuzzer(
-  name = "server_fuzzer",
-  srcs = ["server_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "server_fuzzer_corpus",
-  copts = ["-std=c99"],
+    name = "server_fuzzer",
+    srcs = ["server_fuzzer.c"],
+    language = "C",
+    corpus = "server_fuzzer_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 48e5720..34b5938 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -60,6 +60,7 @@
     'h2_full+pipe': default_unsecure_fixture_options._replace(
         platforms=['linux'], exclude_iomgrs=['uv']),
     'h2_full+trace': default_unsecure_fixture_options._replace(tracing=True),
+    'h2_full+workarounds': default_unsecure_fixture_options,
     'h2_http_proxy': default_unsecure_fixture_options._replace(
         ci_mac=False, exclude_iomgrs=['uv']),
     'h2_oauth2': default_secure_fixture_options._replace(
@@ -151,6 +152,7 @@
     'simple_request': default_test_options,
     'streaming_error_response': default_test_options._replace(cpu_cost=LOWCPU),
     'trailing_metadata': default_test_options,
+    'workaround_cronet_compression': default_test_options,
     'write_buffering': default_test_options._replace(cpu_cost=LOWCPU),
     'write_buffering_at_end': default_test_options._replace(cpu_cost=LOWCPU),
 }
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index e141578..6865aef 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -28,6 +28,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_sh_test", "grpc_cc_binary", "grpc_cc_library")
 
 """Generates the appropriate build.json data for all the end2end tests."""
 
@@ -56,6 +57,7 @@
     'h2_full': fixture_options(),
     'h2_full+pipe': fixture_options(platforms=['linux']),
     'h2_full+trace': fixture_options(tracing=True),
+    'h2_full+workarounds': fixture_options(),
     'h2_http_proxy': fixture_options(),
     'h2_oauth2': fixture_options(),
     'h2_proxy': fixture_options(includes_proxy=True),
@@ -135,6 +137,7 @@
     'trailing_metadata': test_options(),
     'authority_not_supported': test_options(),
     'filter_latency': test_options(),
+    'workaround_cronet_compression': test_options(),
     'write_buffering': test_options(),
     'write_buffering_at_end': test_options(),
 }
@@ -157,7 +160,7 @@
 
 
 def grpc_end2end_tests():
-  native.cc_library(
+  grpc_cc_library(
     name = 'end2end_tests',
     srcs = ['end2end_tests.c', 'end2end_test_utils.c'] + [
              'tests/%s.c' % t
@@ -166,31 +169,33 @@
       'tests/cancel_test_helpers.h',
       'end2end_tests.h'
     ],
-    copts = ['-std=c99'],
+    language = "C",
     deps = [
       ':cq_verifier',
       ':ssl_test_data',
       ':fake_resolver',
       ':http_proxy',
       ':proxy',
-      '//test/core/util:grpc_test_util',
-      '//:grpc',
-      '//test/core/util:gpr_test_util',
-      '//:gpr',
     ]
   )
 
   for f, fopt in END2END_FIXTURES.items():
-    native.cc_binary(
+    grpc_cc_binary(
       name = '%s_test' % f,
       srcs = ['fixtures/%s.c' % f],
-      copts = ['-std=c99'],
-      deps = [':end2end_tests']
+      language = "C",
+      deps = [
+        ':end2end_tests',
+        '//test/core/util:grpc_test_util',
+        '//:grpc',
+        '//test/core/util:gpr_test_util',
+        '//:gpr',
+      ],
     )
     for t, topt in END2END_TESTS.items():
       #print(compatible(fopt, topt), f, t, fopt, topt)
       if not compatible(fopt, topt): continue
-      native.sh_test(
+      grpc_sh_test(
         name = '%s_test@%s' % (f, t),
         srcs = ['end2end_test.sh'],
         args = ['$(location %s_test)' % f, t],
diff --git a/test/core/end2end/tests/workaround_cronet_compression.c b/test/core/end2end/tests/workaround_cronet_compression.c
new file mode 100644
index 0000000..f8ce8c5
--- /dev/null
+++ b/test/core/end2end/tests/workaround_cronet_compression.c
@@ -0,0 +1,411 @@
+/*
+ *
+ * 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 "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/compression.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 "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/surface/call.h"
+#include "src/core/lib/surface/call_test_only.h"
+#include "src/core/lib/transport/static_metadata.h"
+#include "test/core/end2end/cq_verifier.h"
+
+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, "Running test: %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_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), 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->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_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);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+static void request_with_payload_template(
+    grpc_end2end_test_config config, const char *test_name,
+    uint32_t client_send_flags_bitmask,
+    grpc_compression_algorithm default_client_channel_compression_algorithm,
+    grpc_compression_algorithm default_server_channel_compression_algorithm,
+    grpc_compression_algorithm expected_algorithm_from_client,
+    grpc_compression_algorithm expected_algorithm_from_server,
+    grpc_metadata *client_init_metadata, bool set_server_level,
+    grpc_compression_level server_compression_level,
+    char *user_agent_override) {
+  grpc_call *c;
+  grpc_call *s;
+  grpc_slice request_payload_slice;
+  grpc_byte_buffer *request_payload;
+  grpc_channel_args *client_args;
+  grpc_channel_args *server_args;
+  grpc_end2end_test_fixture f;
+  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;
+  grpc_byte_buffer *response_payload_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  cq_verifier *cqv;
+  char request_str[1024];
+  char response_str[1024];
+
+  memset(request_str, 'x', 1023);
+  request_str[1023] = '\0';
+
+  memset(response_str, 'y', 1023);
+  response_str[1023] = '\0';
+
+  request_payload_slice = grpc_slice_from_copied_string(request_str);
+  grpc_slice response_payload_slice =
+      grpc_slice_from_copied_string(response_str);
+
+  client_args = grpc_channel_args_set_compression_algorithm(
+      NULL, default_client_channel_compression_algorithm);
+  server_args = grpc_channel_args_set_compression_algorithm(
+      NULL, default_server_channel_compression_algorithm);
+
+  if (user_agent_override) {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args *client_args_old = client_args;
+    grpc_arg arg;
+    arg.key = GRPC_ARG_PRIMARY_USER_AGENT_STRING;
+    arg.type = GRPC_ARG_STRING;
+    arg.value.string = user_agent_override;
+    client_args = grpc_channel_args_copy_and_add(client_args_old, &arg, 1);
+    grpc_channel_args_destroy(&exec_ctx, client_args_old);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+
+  f = begin_test(config, test_name, client_args, server_args);
+  cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), 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;
+  if (client_init_metadata != NULL) {
+    op->data.send_initial_metadata.count = 1;
+    op->data.send_initial_metadata.metadata = client_init_metadata;
+  } else {
+    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.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->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(100));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(100), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(GPR_BITCOUNT(grpc_call_test_only_get_encodings_accepted_by_peer(
+                 s)) == GRPC_COMPRESS_ALGORITHMS_COUNT);
+  GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
+                        GRPC_COMPRESS_NONE) != 0);
+  GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
+                        GRPC_COMPRESS_DEFLATE) != 0);
+  GPR_ASSERT(GPR_BITGET(grpc_call_test_only_get_encodings_accepted_by_peer(s),
+                        GRPC_COMPRESS_GZIP) != 0);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  if (set_server_level) {
+    op->data.send_initial_metadata.maybe_compression_level.is_set = true;
+    op->data.send_initial_metadata.maybe_compression_level.level =
+        server_compression_level;
+  }
+  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);
+
+  for (int i = 0; i < 2; i++) {
+    request_payload = grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+    response_payload = grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+
+    memset(ops, 0, sizeof(ops));
+    op = ops;
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->data.send_message.send_message = request_payload;
+    op->flags = client_send_flags_bitmask;
+    op->reserved = NULL;
+    op++;
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->data.recv_message.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);
+
+    memset(ops, 0, sizeof(ops));
+    op = ops;
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->data.recv_message.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);
+
+    GPR_ASSERT(request_payload_recv->type == GRPC_BB_RAW);
+    GPR_ASSERT(byte_buffer_eq_string(request_payload_recv, request_str));
+    GPR_ASSERT(request_payload_recv->data.raw.compression ==
+               expected_algorithm_from_client);
+
+    memset(ops, 0, sizeof(ops));
+    op = ops;
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->data.send_message.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);
+    CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
+    cq_verify(cqv);
+
+    GPR_ASSERT(response_payload_recv->type == GRPC_BB_RAW);
+    GPR_ASSERT(byte_buffer_eq_string(response_payload_recv, response_str));
+    if (server_compression_level > GRPC_COMPRESS_LEVEL_NONE) {
+      const grpc_compression_algorithm algo_for_server_level =
+          grpc_call_compression_for_level(s, server_compression_level);
+      GPR_ASSERT(response_payload_recv->data.raw.compression ==
+                 algo_for_server_level);
+    } else {
+      GPR_ASSERT(response_payload_recv->data.raw.compression ==
+                 expected_algorithm_from_server);
+    }
+
+    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);
+  }
+
+  grpc_slice_unref(request_payload_slice);
+  grpc_slice_unref(response_payload_slice);
+
+  memset(ops, 0, sizeof(ops));
+  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);
+
+  memset(ops, 0, sizeof(ops));
+  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;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  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(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_OK);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(was_cancelled == 0);
+
+  grpc_slice_unref(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_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_channel_args_destroy(&exec_ctx, client_args);
+    grpc_channel_args_destroy(&exec_ctx, server_args);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+typedef struct workaround_cronet_compression_config {
+  char *user_agent_override;
+  grpc_compression_algorithm expected_algorithm_from_server;
+} workaround_cronet_compression_config;
+
+static workaround_cronet_compression_config workaround_configs[] = {
+    {NULL, GRPC_COMPRESS_GZIP},
+    {"grpc-objc/1.3.0-dev grpc-c/3.0.0-dev (ios; cronet_http; gentle)",
+     GRPC_COMPRESS_NONE},
+    {"grpc-objc/1.3.0-dev grpc-c/3.0.0-dev (ios; chttp2; gentle)",
+     GRPC_COMPRESS_GZIP},
+    {"grpc-objc/1.4.0 grpc-c/3.0.0-dev (ios; cronet_http; gentle)",
+     GRPC_COMPRESS_GZIP}};
+static const size_t workaround_configs_num =
+    sizeof(workaround_configs) / sizeof(*workaround_configs);
+
+static void test_workaround_cronet_compression(
+    grpc_end2end_test_config config) {
+  for (uint32_t i = 0; i < workaround_configs_num; i++) {
+    request_with_payload_template(
+        config, "test_invoke_request_with_compressed_payload", 0,
+        GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP, GRPC_COMPRESS_GZIP,
+        workaround_configs[i].expected_algorithm_from_server, NULL, false,
+        /* ignored */ GRPC_COMPRESS_LEVEL_NONE,
+        workaround_configs[i].user_agent_override);
+  }
+}
+
+void workaround_cronet_compression(grpc_end2end_test_config config) {
+  if (config.feature_mask & FEATURE_MASK_SUPPORTS_WORKAROUNDS) {
+    test_workaround_cronet_compression(config);
+  }
+}
+
+void workaround_cronet_compression_pre_init(void) {}
diff --git a/test/core/fling/BUILD b/test/core/fling/BUILD
index 0b0ebcb..8f17527 100644
--- a/test/core/fling/BUILD
+++ b/test/core/fling/BUILD
@@ -27,36 +27,68 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cc_binary(
+grpc_cc_binary(
     name = "client",
+    testonly = 1,
     srcs = ["client.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
-    testonly = 1,
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "server",
-    srcs = ["server.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
     testonly = 1,
-    copts = ['-std=c99']
+    srcs = ["server.c"],
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "fling",
     srcs = ["fling_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
-    data = [":client", ":server"]
+    data = [
+        ":client",
+        ":server",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "fling_stream",
     srcs = ["fling_stream_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
-    data = [":client", ":server"]
+    data = [
+        ":client",
+        ":server",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/handshake/BUILD b/test/core/handshake/BUILD
index 996b503..bdb91ea 100644
--- a/test/core/handshake/BUILD
+++ b/test/core/handshake/BUILD
@@ -27,12 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "client_ssl",
     srcs = ["client_ssl.c"],
-    copts = ["-std=c99"],
+    language = "C",
     data = [
         "//src/core/tsi/test_creds:ca.pem",
         "//src/core/tsi/test_creds:server1.key",
@@ -46,10 +48,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "server_ssl",
     srcs = ["server_ssl.c"],
-    copts = ["-std=c99"],
+    language = "C",
     data = [
         "//src/core/tsi/test_creds:ca.pem",
         "//src/core/tsi/test_creds:server1.key",
diff --git a/test/core/http/BUILD b/test/core/http/BUILD
index abfa759..9350dac 100644
--- a/test/core/http/BUILD
+++ b/test/core/http/BUILD
@@ -27,24 +27,34 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "response_fuzzer",
-  srcs = ["response_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "response_corpus",
-  copts = ["-std=c99"],
+    name = "response_fuzzer",
+    srcs = ["response_fuzzer.c"],
+    language = "C",
+    corpus = "response_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_fuzzer(
-  name = "request_fuzzer",
-  srcs = ["request_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "request_corpus",
-  copts = ["-std=c99"],
+    name = "request_fuzzer",
+    srcs = ["request_fuzzer.c"],
+    language = "C",
+    corpus = "request_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 # Copyright 2017, Google Inc.
@@ -80,25 +90,43 @@
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cc_test(
+grpc_cc_test(
     name = "httpcli_test",
     srcs = ["httpcli_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
-    copts = ['-std=c99'],
-    data = ['test_server.py']
+    language = "C",
+    data = ["test_server.py"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "httpscli_test",
     srcs = ["httpscli_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
-    copts = ['-std=c99'],
-    data = ['test_server.py']
+    language = "C",
+    data = ["test_server.py"],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "parser_test",
     srcs = ["parser_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/end2end:ssl_test_data"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/iomgr/BUILD b/test/core/iomgr/BUILD
index 808faf5..269ca94 100644
--- a/test/core/iomgr/BUILD
+++ b/test/core/iomgr/BUILD
@@ -27,155 +27,266 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
-cc_library(
+package(default_visibility = ["//visibility:public"]) # Useful for third party devs to test their io manager implementation.
+
+grpc_cc_library(
     name = "endpoint_tests",
     srcs = ["endpoint_tests.c"],
     hdrs = ["endpoint_tests.h"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
+    language = "C",
     visibility = ["//test:__subpackages__"],
-    copts = ['-std=c99']
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "combiner_test",
     srcs = ["combiner_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "endpoint_pair_test",
     srcs = ["endpoint_pair_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", ":endpoint_tests"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        ":endpoint_tests",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "ev_epollsig_linux_test",
     srcs = ["ev_epollsig_linux_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
+    language = "C",
 )
 
-cc_test(
+grpc_cc_test(
     name = "fd_conservation_posix_test",
     srcs = ["fd_conservation_posix_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "fd_posix_test",
     srcs = ["fd_posix_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "load_file_test",
     srcs = ["load_file_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "pollset_set_test",
     srcs = ["pollset_set_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "resolve_address_posix_test",
     srcs = ["resolve_address_posix_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "resolve_address_test",
     srcs = ["resolve_address_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "resource_quota_test",
     srcs = ["resource_quota_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "sockaddr_utils_test",
     srcs = ["sockaddr_utils_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "socket_utils_test",
     srcs = ["socket_utils_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "tcp_client_posix_test",
     srcs = ["tcp_client_posix_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "tcp_posix_test",
     srcs = ["tcp_posix_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", ":endpoint_tests"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        ":endpoint_tests",
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "tcp_server_posix_test",
     srcs = ["tcp_server_posix_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "time_averaged_stats_test",
     srcs = ["time_averaged_stats_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "timer_heap_test",
     srcs = ["timer_heap_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "timer_list_test",
     srcs = ["timer_list_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "udp_server_test",
     srcs = ["udp_server_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "wakeup_fd_cv_test",
     srcs = ["wakeup_fd_cv_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/json/BUILD b/test/core/json/BUILD
index f5a877e..aba2e2c 100644
--- a/test/core/json/BUILD
+++ b/test/core/json/BUILD
@@ -27,44 +27,75 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "json_fuzzer",
-  srcs = ["fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "corpus",
-  copts = ["-std=c99"],
+    name = "json_fuzzer",
+    srcs = ["fuzzer.c"],
+    language = "C",
+    corpus = "corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "json_rewrite",
-    srcs = ["json_rewrite.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
     testonly = 1,
-    copts = ['-std=c99']
+    srcs = ["json_rewrite.c"],
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "json_rewrite_test",
     srcs = ["json_rewrite_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99'],
-    data = ["rewrite_test_input.json", "rewrite_test_output_condensed.json", "rewrite_test_output_indented.json", ":json_stream_error_test"]
+    language = "C",
+    data = [
+        "rewrite_test_input.json",
+        "rewrite_test_output_condensed.json",
+        "rewrite_test_output_indented.json",
+        ":json_stream_error_test",
+    ],
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "json_stream_error_test",
     srcs = ["json_stream_error_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "json_test",
     srcs = ["json_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/nanopb/BUILD b/test/core/nanopb/BUILD
index b02d750..33e9338 100644
--- a/test/core/nanopb/BUILD
+++ b/test/core/nanopb/BUILD
@@ -27,23 +27,32 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "fuzzer_response",
-  srcs = ["fuzzer_response.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "corpus_response",
-  copts = ["-std=c99"],
+    name = "fuzzer_response",
+    srcs = ["fuzzer_response.c"],
+    language = "C",
+    corpus = "corpus_response",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 grpc_fuzzer(
-  name = "fuzzer_serverlist",
-  srcs = ["fuzzer_serverlist.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "corpus_serverlist",
-  copts = ["-std=c99"],
+    name = "fuzzer_serverlist",
+    srcs = ["fuzzer_serverlist.c"],
+    language = "C",
+    corpus = "corpus_serverlist",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
-
diff --git a/test/core/network_benchmarks/BUILD b/test/core/network_benchmarks/BUILD
index a5209de..5c243f7 100644
--- a/test/core/network_benchmarks/BUILD
+++ b/test/core/network_benchmarks/BUILD
@@ -27,11 +27,18 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_binary(
+grpc_cc_binary(
     name = "low_level_ping_pong",
     srcs = ["low_level_ping_pong.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/security/BUILD b/test/core/security/BUILD
index a81e1d3..b2d8774 100644
--- a/test/core/security/BUILD
+++ b/test/core/security/BUILD
@@ -27,72 +27,110 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "ssl_server_fuzzer",
-  srcs = ["ssl_server_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util", "//test/core/end2end:ssl_test_data"],
-  corpus = "corpus",
-  copts = ["-std=c99"],
+    name = "ssl_server_fuzzer",
+    srcs = ["ssl_server_fuzzer.c"],
+    language = "C",
+    corpus = "corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/end2end:ssl_test_data",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "oauth2_utils",
     srcs = ["oauth2_utils.c"],
     hdrs = ["oauth2_utils.h"],
+    language = "C",
     deps = ["//:grpc"],
-    copts = ['-std=c99'],
     visibility = ["//test/cpp:__subpackages__"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "auth_context_test",
     srcs = ["auth_context_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "credentials_test",
     srcs = ["credentials_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "secure_endpoint_test",
     srcs = ["secure_endpoint_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util", "//test/core/iomgr:endpoint_tests"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/iomgr:endpoint_tests",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "security_connector_test",
     srcs = ["security_connector_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "create_jwt",
     srcs = ["create_jwt.c"],
-    deps = ["//:grpc", "//:gpr"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+    ],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "fetch_oauth2",
     srcs = ["fetch_oauth2.c"],
-    deps = ["//:grpc", "//:gpr", ":oauth2_utils"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        ":oauth2_utils",
+        "//:gpr",
+        "//:grpc",
+    ],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "verify_jwt",
     srcs = ["verify_jwt.c"],
-    deps = ["//:grpc", "//:gpr"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+    ],
 )
diff --git a/test/core/slice/BUILD b/test/core/slice/BUILD
index 18cf6f6..8dc34e7 100644
--- a/test/core/slice/BUILD
+++ b/test/core/slice/BUILD
@@ -27,56 +27,77 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "percent_decode_fuzzer",
-  srcs = ["percent_decode_fuzzer.c"],
-  deps = ["//:gpr", "//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "response_corpus",
-  copts = ["-std=c99"],
+    name = "percent_decode_fuzzer",
+    srcs = ["percent_decode_fuzzer.c"],
+    language = "C",
+    corpus = "response_corpus",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "percent_encoding_test",
     srcs = ["percent_encoding_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "slice_test",
     srcs = ["slice_test.c"],
     deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
 )
 
-cc_test(
+grpc_cc_test(
     name = "slice_string_helpers_test",
     srcs = ["slice_string_helpers_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "slice_buffer_test",
     srcs = ["slice_buffer_test.c"],
     deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
 )
 
-cc_test(
+grpc_cc_test(
     name = "slice_hash_table_test",
     srcs = ["slice_hash_table_test.c"],
     deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
 )
 
-cc_test(
+grpc_cc_test(
     name = "b64_test",
     srcs = ["b64_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/support/BUILD b/test/core/support/BUILD
index 3183510..db40819 100644
--- a/test/core/support/BUILD
+++ b/test/core/support/BUILD
@@ -27,137 +27,196 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "alloc_test",
     srcs = ["alloc_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "avl_test",
     srcs = ["avl_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "backoff_test",
     srcs = ["backoff_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "cmdline_test",
     srcs = ["cmdline_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "cpu_test",
     srcs = ["cpu_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "env_test",
     srcs = ["env_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "histogram_test",
     srcs = ["histogram_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "host_port_test",
     srcs = ["host_port_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "log_test",
     srcs = ["log_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "mpscq_test",
     srcs = ["mpscq_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "murmur_hash_test",
     srcs = ["murmur_hash_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "stack_lockfree_test",
     srcs = ["stack_lockfree_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "string_test",
     srcs = ["string_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "spinlock_test",
     srcs = ["spinlock_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "sync_test",
     srcs = ["sync_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "thd_test",
     srcs = ["thd_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "time_test",
     srcs = ["time_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "tls_test",
     srcs = ["tls_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "useful_test",
     srcs = ["useful_test.c"],
-    deps = ["//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//test/core/util:gpr_test_util",
+    ],
 )
diff --git a/test/core/surface/BUILD b/test/core/surface/BUILD
index 3d5e26c..44d37da 100644
--- a/test/core/surface/BUILD
+++ b/test/core/surface/BUILD
@@ -27,12 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "alarm_test",
     srcs = ["alarm_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -41,10 +43,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "grpc_byte_buffer_reader_test",
     srcs = ["byte_buffer_reader_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -53,10 +55,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "channel_create_test",
     srcs = ["channel_create_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -65,10 +67,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "grpc_completion_queue_test",
     srcs = ["completion_queue_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -77,10 +79,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "concurrent_connectivity_test",
     srcs = ["concurrent_connectivity_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -89,10 +91,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "init_test",
     srcs = ["init_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -101,10 +103,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "grpc_invalid_channel_args_test",
     srcs = ["invalid_channel_args_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -113,10 +115,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "lame_client_test",
     srcs = ["lame_client_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -126,10 +128,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "public_headers_must_be_c89",
     srcs = ["public_headers_must_be_c89.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -138,10 +140,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "secure_channel_create_test",
     srcs = ["secure_channel_create_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -150,10 +152,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "sequential_connectivity_test",
     srcs = ["sequential_connectivity_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -163,10 +165,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "server_chttp2_test",
     srcs = ["server_chttp2_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
@@ -175,10 +177,10 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "server_test",
     srcs = ["server_test.c"],
-    copts = ["-std=c99"],
+    language = "C",
     deps = [
         "//:gpr",
         "//:grpc",
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 330da46..aa4769c 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -73,5 +73,6 @@
 #include <grpc/support/time.h>
 #include <grpc/support/tls.h>
 #include <grpc/support/useful.h>
+#include <grpc/support/workaround_list.h>
 
 int main(int argc, char **argv) { return 0; }
diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD
index 08b2fd3..2628c89 100644
--- a/test/core/transport/BUILD
+++ b/test/core/transport/BUILD
@@ -27,53 +27,90 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "bdp_estimator_test",
     srcs = ["bdp_estimator_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "connectivity_state_test",
     srcs = ["connectivity_state_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "metadata_test",
     srcs = ["metadata_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "pid_controller_test",
     srcs = ["pid_controller_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "status_conversion_test",
     srcs = ["status_conversion_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "stream_owned_slice_test",
     srcs = ["stream_owned_slice_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "timeout_encoding_test",
     srcs = ["timeout_encoding_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/transport/chttp2/BUILD b/test/core/transport/chttp2/BUILD
index b507e27..af2a4ae 100644
--- a/test/core/transport/chttp2/BUILD
+++ b/test/core/transport/chttp2/BUILD
@@ -27,69 +27,114 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
 load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
 
 grpc_fuzzer(
-  name = "hpack_parser_fuzzer",
-  srcs = ["hpack_parser_fuzzer_test.c"],
-  deps = ["//:grpc", "//test/core/util:grpc_test_util"],
-  corpus = "hpack_parser_corpus"
+    name = "hpack_parser_fuzzer",
+    srcs = ["hpack_parser_fuzzer_test.c"],
+    corpus = "hpack_parser_corpus",
+    deps = [
+        "//:grpc",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "alpn_test",
     srcs = ["alpn_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bin_decoder_test",
     srcs = ["bin_decoder_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bin_encoder_test",
     srcs = ["bin_encoder_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "hpack_encoder_test",
     srcs = ["hpack_encoder_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "hpack_parser_test",
     srcs = ["hpack_parser_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "hpack_table_test",
     srcs = ["hpack_table_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "stream_map_test",
     srcs = ["stream_map_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "varint_test",
     srcs = ["varint_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/tsi/BUILD b/test/core/tsi/BUILD
index e6cba34..a0f2910 100644
--- a/test/core/tsi/BUILD
+++ b/test/core/tsi/BUILD
@@ -27,11 +27,18 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+grpc_cc_test(
     name = "transport_security_test",
     srcs = ["transport_security_test.c"],
-    deps = ["//:grpc", "//test/core/util:grpc_test_util", "//:gpr", "//test/core/util:gpr_test_util"],
-    copts = ['-std=c99']
+    language = "C",
+    deps = [
+        "//:gpr",
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+        "//test/core/util:grpc_test_util",
+    ],
 )
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 03c79f1..6b99462 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -27,23 +27,26 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_cc_binary")
+
 licenses(["notice"])  # 3-clause BSD
 
-cc_library(
+package(default_visibility = ["//visibility:public"])
+
+grpc_cc_library(
     name = "gpr_test_util",
     srcs = [
-        "test_config.c",
         "memory_counters.c",
+        "test_config.c",
     ],
     hdrs = [
-        "test_config.h",
         "memory_counters.h",
+        "test_config.h",
     ],
     deps = ["//:gpr"],
-    visibility = ["//:__subpackages__"],
 )
 
-cc_library(
+grpc_cc_library(
     name = "grpc_test_util",
     srcs = [
         "debugger_macros.c",
@@ -60,7 +63,6 @@
     ],
     hdrs = [
         "debugger_macros.h",
-        "trickle_endpoint.h",
         "grpc_profiler.h",
         "mock_endpoint.h",
         "parse_hexstring.h",
@@ -70,21 +72,25 @@
         "reconnect_server.h",
         "slice_splitter.h",
         "test_tcp_server.h",
+        "trickle_endpoint.h",
     ],
-    deps = [":gpr_test_util", "//:grpc"],
-    visibility = ["//test:__subpackages__"],
-    copts = ["-std=c99"],
+    language = "C",
+    deps = [
+        ":gpr_test_util",
+        "//:grpc",
+    ],
 )
 
-cc_library(
-  name = "one_corpus_entry_fuzzer",
-  srcs = ["one_corpus_entry_fuzzer.c"],
-  deps = [":gpr_test_util", "//:grpc"],
-  visibility = ["//test:__subpackages__"],
+grpc_cc_library(
+    name = "one_corpus_entry_fuzzer",
+    srcs = ["one_corpus_entry_fuzzer.c"],
+    deps = [
+        ":gpr_test_util",
+        "//:grpc",
+    ],
 )
 
 sh_library(
-  name = "fuzzer_one_entry_runner",
-  srcs = ["fuzzer_one_entry_runner.sh"],
-  visibility = ["//test:__subpackages__"],
+    name = "fuzzer_one_entry_runner",
+    srcs = ["fuzzer_one_entry_runner.sh"],
 )
diff --git a/test/core/util/grpc_fuzzer.bzl b/test/core/util/grpc_fuzzer.bzl
index 2f552a9..2fcb58b 100644
--- a/test/core/util/grpc_fuzzer.bzl
+++ b/test/core/util/grpc_fuzzer.bzl
@@ -27,8 +27,10 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_binary")
+
 def grpc_fuzzer(name, corpus, srcs = [], deps = [], **kwargs):
-  native.cc_binary(
+  grpc_cc_binary(
     name = '%s/one_entry.bin' % name,
     srcs = srcs,
     deps = deps + ["//test/core/util:one_corpus_entry_fuzzer"],
diff --git a/test/core/util/port.c b/test/core/util/port.c
index da1ed4e..271ff22 100644
--- a/test/core/util/port.c
+++ b/test/core/util/port.c
@@ -77,9 +77,11 @@
 
 static void free_chosen_ports(void) {
   size_t i;
+  grpc_init();
   for (i = 0; i < num_chosen_ports; i++) {
     grpc_free_port_using_server(chosen_ports[i]);
   }
+  grpc_shutdown();
   gpr_free(chosen_ports);
 }
 
diff --git a/test/cpp/codegen/BUILD b/test/cpp/codegen/BUILD
index 43d133f..f974e63 100644
--- a/test/cpp/codegen/BUILD
+++ b/test/cpp/codegen/BUILD
@@ -29,37 +29,45 @@
 
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
+
+grpc_cc_test(
     name = "codegen_test_full",
     srcs = ["codegen_test_full.cc"],
     deps = [
         "//:grpc++",
-        "//external:gtest",
         "//test/core/util:gpr_test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "codegen_test_minimal",
     srcs = ["codegen_test_minimal.cc"],
     deps = [
         "//:grpc++",
-        "//external:gtest",
         "//test/core/util:gpr_test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "proto_utils_test",
     srcs = ["proto_utils_test.cc"],
     deps = [
         "//:grpc++",
-        "//external:gtest",
         "//test/core/util:gpr_test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "golden_file_test",
     srcs = ["golden_file_test.cc"],
     args = ["--generated_file_path=$(GENDIR)/src/proto/grpc/testing/"],
@@ -69,9 +77,11 @@
     ],
     deps = [
         "//:grpc++",
-        "//external:gflags",
-        "//external:gtest",
         "//src/proto/grpc/testing:compiler_test_proto",
         "//test/core/util:gpr_test_util",
     ],
+    external_deps = [
+        "gtest",
+        "gflags",
+    ],
 )
diff --git a/test/cpp/common/BUILD b/test/cpp/common/BUILD
index 48ad583..c8b3e46 100644
--- a/test/cpp/common/BUILD
+++ b/test/cpp/common/BUILD
@@ -29,32 +29,66 @@
 
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
+
+grpc_cc_test(
     name = "alarm_cpp_test",
     srcs = ["alarm_cpp_test.cc"],
-    deps = ["//:grpc++", "//external:gtest", "//test/core/util:gpr_test_util"],
+    deps = [
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "auth_property_iterator_test",
     srcs = ["auth_property_iterator_test.cc"],
-    deps = ["//:grpc++", "//external:gtest", "//test/core/util:gpr_test_util", "//test/cpp/util:test_util"],
+    deps = [
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+        "//test/cpp/util:test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "channel_arguments_test",
     srcs = ["channel_arguments_test.cc"],
-    deps = ["//:grpc++", "//external:gtest", "//test/core/util:gpr_test_util"],
+    deps = [
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "channel_filter_test",
     srcs = ["channel_filter_test.cc"],
-    deps = ["//:grpc++", "//external:gtest", "//test/core/util:gpr_test_util"],
+    deps = [
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "secure_auth_context_test",
     srcs = ["secure_auth_context_test.cc"],
-    deps = ["//:grpc++", "//external:gtest", "//test/core/util:gpr_test_util", "//test/cpp/util:test_util"],
+    deps = [
+        "//:grpc++",
+        "//test/core/util:gpr_test_util",
+        "//test/cpp/util:test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
 )
diff --git a/test/cpp/end2end/BUILD b/test/cpp/end2end/BUILD
index e867493..9b691a8 100644
--- a/test/cpp/end2end/BUILD
+++ b/test/cpp/end2end/BUILD
@@ -29,25 +29,30 @@
 
 licenses(["notice"])  # 3-clause BSD
 
-cc_library(
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test")
+
+package(default_visibility=["//visibility:public"]) # Allows external users to implement end2end tests.
+
+grpc_cc_library(
     name = "test_service_impl",
     srcs = ["test_service_impl.cc"],
     hdrs = ["test_service_impl.h"],
     deps = [
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_proto",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "async_end2end_test",
     srcs = ["async_end2end_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/health/v1:health_proto",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
@@ -56,16 +61,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "client_crash_test",
     srcs = ["client_crash_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -73,17 +80,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "client_crash_test_server",
     srcs = ["client_crash_test_server.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gflags",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -91,17 +99,21 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gflags",
+        "gtest",
+    ],
 )
 
-cc_test(
-    name = "end2end_test",
+grpc_cc_library(
+    name = "end2end_test_lib",
     srcs = ["end2end_test.cc"],
+    testonly = True,
     deps = [
         ":test_service_impl",
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -109,16 +121,25 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
+    name = "end2end_test",
+    deps = [
+        ":end2end_test_lib"
+    ],
+)
+
+grpc_cc_test(
     name = "filter_end2end_test",
     srcs = ["filter_end2end_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -126,16 +147,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "generic_end2end_test",
     srcs = ["generic_end2end_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -143,9 +166,12 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "hybrid_end2end_test",
     srcs = ["hybrid_end2end_test.cc"],
     deps = [
@@ -153,7 +179,6 @@
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -161,16 +186,19 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "mock_test",
     srcs = ["mock_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
+        "//:grpc++_test",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -178,9 +206,12 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "round_robin_end2end_test",
     srcs = ["round_robin_end2end_test.cc"],
     deps = [
@@ -188,7 +219,6 @@
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -196,10 +226,12 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-
-cc_test(
+grpc_cc_test(
     name = "grpclb_end2end_test",
     srcs = ["grpclb_end2end_test.cc"],
     deps = [
@@ -207,7 +239,6 @@
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/lb/v1:load_balancer_proto",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
@@ -217,9 +248,12 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "proto_server_reflection_test",
     srcs = ["proto_server_reflection_test.cc"],
     deps = [
@@ -228,8 +262,6 @@
         "//:grpc",
         "//:grpc++",
         "//:grpc++_reflection",
-        "//external:gflags",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -238,9 +270,13 @@
         "//test/cpp/util:grpc++_proto_reflection_desc_db",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+        "gflags",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "server_builder_plugin_test",
     srcs = ["server_builder_plugin_test.cc"],
     deps = [
@@ -248,7 +284,6 @@
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -256,16 +291,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "server_crash_test",
     srcs = ["server_crash_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -273,17 +310,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "server_crash_test_client",
     srcs = ["server_crash_test_client.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gflags",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -291,16 +329,19 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gflags",
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "shutdown_test",
     srcs = ["shutdown_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -308,16 +349,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "streaming_throughput_test",
     srcs = ["streaming_throughput_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -325,16 +368,18 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "thread_stress_test",
     srcs = ["thread_stress_test.cc"],
     deps = [
         "//:gpr",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:echo_messages_proto",
         "//src/proto/grpc/testing:echo_proto",
         "//src/proto/grpc/testing/duplicate:echo_duplicate_proto",
@@ -342,4 +387,7 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index cc3958b..8d59cbb 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -47,7 +47,6 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/tls.h>
-#include <gtest/gtest.h>
 
 #include "src/core/lib/iomgr/port.h"
 #include "src/proto/grpc/health/v1/health.grpc.pb.h"
@@ -58,6 +57,8 @@
 #include "test/cpp/util/string_ref_helper.h"
 #include "test/cpp/util/test_credentials_provider.h"
 
+#include <gtest/gtest.h>
+
 #ifdef GRPC_POSIX_SOCKET
 #include "src/core/lib/iomgr/ev_posix.h"
 #endif
diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc
index 966c04b..0ea5209 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -41,7 +41,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -49,6 +48,8 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/subprocess.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index df71777..9a9e818 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -48,7 +48,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.h>
 
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
@@ -59,6 +58,8 @@
 #include "test/cpp/util/string_ref_helper.h"
 #include "test/cpp/util/test_credentials_provider.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using grpc::testing::kTlsCredentialsType;
diff --git a/test/cpp/end2end/filter_end2end_test.cc b/test/cpp/end2end/filter_end2end_test.cc
index 2f873ee..5589e2f 100644
--- a/test/cpp/end2end/filter_end2end_test.cc
+++ b/test/cpp/end2end/filter_end2end_test.cc
@@ -48,7 +48,6 @@
 #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"
@@ -56,6 +55,8 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/byte_buffer_proto_helper.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 25c221b..281c58e 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -46,13 +46,14 @@
 #include <grpc/grpc.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.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"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
@@ -115,6 +116,10 @@
   void client_fail(int i) { verify_ok(&cli_cq_, i, false); }
 
   void SendRpc(int num_rpcs) {
+    SendRpc(num_rpcs, false, gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  }
+
+  void SendRpc(int num_rpcs, bool check_deadline, gpr_timespec deadline) {
     const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo");
     for (int i = 0; i < num_rpcs; i++) {
       EchoRequest send_request;
@@ -129,6 +134,11 @@
 
       // The string needs to be long enough to test heap-based slice.
       send_request.set_message("Hello world. Hello world. Hello world.");
+
+      if (check_deadline) {
+        cli_ctx.set_deadline(deadline);
+      }
+
       std::unique_ptr<GenericClientAsyncReaderWriter> call =
           generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
       client_ok(1);
@@ -147,6 +157,12 @@
       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());
+
+      if (check_deadline) {
+        EXPECT_TRUE(gpr_time_similar(deadline, srv_ctx.raw_deadline(),
+                                     gpr_time_from_millis(100, GPR_TIMESPAN)));
+      }
+
       ByteBuffer recv_buffer;
       stream.Read(&recv_buffer, tag(5));
       server_ok(5);
@@ -262,6 +278,12 @@
   EXPECT_TRUE(recv_status.ok());
 }
 
+TEST_F(GenericEnd2endTest, Deadline) {
+  ResetStub();
+  SendRpc(1, true, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                gpr_time_from_seconds(10, GPR_TIMESPAN)));
+}
+
 }  // namespace
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/end2end/health_service_end2end_test.cc b/test/cpp/end2end/health_service_end2end_test.cc
index 3d51007..c320c78 100644
--- a/test/cpp/end2end/health_service_end2end_test.cc
+++ b/test/cpp/end2end/health_service_end2end_test.cc
@@ -46,7 +46,6 @@
 #include <grpc++/server_context.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <gtest/gtest.h>
 
 #include "src/proto/grpc/health/v1/health.grpc.pb.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
@@ -55,6 +54,8 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/end2end/test_service_impl.h"
 
+#include <gtest/gtest.h>
+
 using grpc::health::v1::Health;
 using grpc::health::v1::HealthCheckRequest;
 using grpc::health::v1::HealthCheckResponse;
diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc
index a4ba76f..1cd515a 100644
--- a/test/cpp/end2end/hybrid_end2end_test.cc
+++ b/test/cpp/end2end/hybrid_end2end_test.cc
@@ -42,7 +42,6 @@
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
 #include <grpc/grpc.h>
-#include <gtest/gtest.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -51,6 +50,8 @@
 #include "test/cpp/end2end/test_service_impl.h"
 #include "test/cpp/util/byte_buffer_proto_helper.h"
 
+#include <gtest/gtest.h>
+
 namespace grpc {
 namespace testing {
 
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index 7e33006..3a82b3a 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -45,7 +45,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.h>
 
 #include <grpc++/test/mock_stream.h>
 
@@ -55,6 +54,8 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+#include <gtest/gtest.h>
+
 #include <iostream>
 
 using namespace std;
diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc
index 8b9688d..25cb0d5 100644
--- a/test/cpp/end2end/proto_server_reflection_test.cc
+++ b/test/cpp/end2end/proto_server_reflection_test.cc
@@ -41,7 +41,6 @@
 #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 "test/core/util/port.h"
@@ -49,6 +48,8 @@
 #include "test/cpp/end2end/test_service_impl.h"
 #include "test/cpp/util/proto_reflection_descriptor_database.h"
 
+#include <gtest/gtest.h>
+
 namespace grpc {
 namespace testing {
 
diff --git a/test/cpp/end2end/round_robin_end2end_test.cc b/test/cpp/end2end/round_robin_end2end_test.cc
index cc340b9..f8e3cc0 100644
--- a/test/cpp/end2end/round_robin_end2end_test.cc
+++ b/test/cpp/end2end/round_robin_end2end_test.cc
@@ -44,13 +44,14 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.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/end2end/test_service_impl.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
diff --git a/test/cpp/end2end/server_builder_plugin_test.cc b/test/cpp/end2end/server_builder_plugin_test.cc
index 1b6f4ce..81b747a 100644
--- a/test/cpp/end2end/server_builder_plugin_test.cc
+++ b/test/cpp/end2end/server_builder_plugin_test.cc
@@ -45,13 +45,14 @@
 #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 "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/end2end/test_service_impl.h"
 
+#include <gtest/gtest.h>
+
 #define PLUGIN_NAME "TestServerBuilderPlugin"
 
 namespace grpc {
diff --git a/test/cpp/end2end/server_crash_test.cc b/test/cpp/end2end/server_crash_test.cc
index b1f9216..4b7041a 100644
--- a/test/cpp/end2end/server_crash_test.cc
+++ b/test/cpp/end2end/server_crash_test.cc
@@ -41,7 +41,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.h>
 
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
@@ -49,6 +48,8 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/subprocess.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc
index bd68e85..63b397d 100644
--- a/test/cpp/end2end/shutdown_test.cc
+++ b/test/cpp/end2end/shutdown_test.cc
@@ -33,8 +33,6 @@
 
 #include <thread>
 
-#include <gtest/gtest.h>
-
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
@@ -51,6 +49,8 @@
 #include "test/core/util/test_config.h"
 #include "test/cpp/util/test_credentials_provider.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 
diff --git a/test/cpp/end2end/streaming_throughput_test.cc b/test/cpp/end2end/streaming_throughput_test.cc
index 3025837..ec5b83d 100644
--- a/test/cpp/end2end/streaming_throughput_test.cc
+++ b/test/cpp/end2end/streaming_throughput_test.cc
@@ -35,8 +35,6 @@
 #include <mutex>
 #include <thread>
 
-#include <gtest/gtest.h>
-
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
@@ -56,6 +54,8 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
index b473dd1..5411b35 100644
--- a/test/cpp/end2end/test_service_impl.cc
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -40,11 +40,11 @@
 #include <grpc++/server_context.h>
 #include <grpc/support/log.h>
 
-#include <gtest/gtest.h>
-
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/cpp/util/string_ref_helper.h"
 
+#include <gtest/gtest.h>
+
 using std::chrono::system_clock;
 
 namespace grpc {
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index d353f98..defa789 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -43,7 +43,6 @@
 #include <grpc/grpc.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.h>
 
 #include "src/core/lib/surface/api_trace.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
@@ -51,6 +50,8 @@
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
+#include <gtest/gtest.h>
+
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD
index 208ac6d..3a968a0 100644
--- a/test/cpp/microbenchmarks/BUILD
+++ b/test/cpp/microbenchmarks/BUILD
@@ -29,14 +29,17 @@
 
 licenses(["notice"])  # 3-clause BSD
 
-cc_test(
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library")
+
+grpc_cc_test(
     name = "noop-benchmark",
     srcs = ["noop-benchmark.cc"],
-    linkopts = ["-pthread"],
-    deps = ["//external:benchmark"],
+    external_deps = [
+        "benchmark",
+    ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "helpers",
     srcs = ["helpers.cc"],
     hdrs = [
@@ -44,64 +47,68 @@
         "fullstack_fixtures.h",
         "helpers.h",
     ],
-    linkopts = ["-pthread"],
     deps = [
         "//:grpc++",
-        "//external:benchmark",
         "//src/proto/grpc/testing:echo_proto",
         "//test/core/util:grpc_test_util",
     ],
+    external_deps = [
+        "benchmark",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_closure",
     srcs = ["bm_closure.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_cq",
     srcs = ["bm_cq.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_cq_multiple_threads",
     srcs = ["bm_cq_multiple_threads.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_error",
     srcs = ["bm_error.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_fullstack_streaming_ping_pong",
     srcs = ["bm_fullstack_streaming_ping_pong.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_fullstack_streaming_pump",
     srcs = ["bm_fullstack_streaming_pump.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_fullstack_trickle",
     srcs = ["bm_fullstack_trickle.cc"],
-    deps = [":helpers", "//external:gflags"],
+    deps = [":helpers"],
+    external_deps = [
+        "gflags",
+    ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_fullstack_unary_ping_pong",
     srcs = ["bm_fullstack_unary_ping_pong.cc"],
     deps = [":helpers"],
 )
 
-cc_test(
+grpc_cc_test(
     name = "bm_metadata",
     srcs = ["bm_metadata.cc"],
     deps = [":helpers"],
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
index 0d267da..704f255 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -81,10 +81,16 @@
   gpr_free(cq_completion);
 }
 
-/* Queues a completion tag. ZERO polling overhead */
+/* Queues a completion tag if deadline is > 0.
+ * Does nothing if deadline is 0 (i.e gpr_time_0(GPR_CLOCK_MONOTONIC)) */
 static grpc_error* pollset_work(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
                                 grpc_pollset_worker** worker, gpr_timespec now,
                                 gpr_timespec deadline) {
+  if (gpr_time_cmp(deadline, gpr_time_0(GPR_CLOCK_MONOTONIC)) == 0) {
+    gpr_log(GPR_ERROR, "no-op");
+    return GRPC_ERROR_NONE;
+  }
+
   gpr_mu_unlock(&ps->mu);
   grpc_cq_begin_op(g_cq, g_tag);
   grpc_cq_end_op(exec_ctx, g_cq, g_tag, GRPC_ERROR_NONE, cq_done_cb, NULL,
@@ -115,6 +121,14 @@
 
 static void teardown() {
   grpc_completion_queue_shutdown(g_cq);
+
+  /* Drain any events */
+  gpr_timespec deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
+  while (grpc_completion_queue_next(g_cq, deadline, NULL).type !=
+         GRPC_QUEUE_SHUTDOWN) {
+    /* Do nothing */
+  }
+
   grpc_completion_queue_destroy(g_cq);
 }
 
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index 98aca1c..aa71c2a 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -100,6 +100,12 @@
     }
   }
 
+  void AddToLabel(std::ostream& out, benchmark::State& state) {
+    BaseFixture::AddToLabel(out, state);
+    out << " polls/iter:"
+        << (double)grpc_get_cq_poll_num(this->cq()->cq()) / state.iterations();
+  }
+
   ServerCompletionQueue* cq() { return cq_.get(); }
   std::shared_ptr<Channel> channel() { return channel_; }
 
@@ -212,6 +218,12 @@
     }
   }
 
+  void AddToLabel(std::ostream& out, benchmark::State& state) {
+    BaseFixture::AddToLabel(out, state);
+    out << " polls/iter:"
+        << (double)grpc_get_cq_poll_num(this->cq()->cq()) / state.iterations();
+  }
+
   ServerCompletionQueue* cq() { return cq_.get(); }
   std::shared_ptr<Channel> channel() { return channel_; }
 
@@ -245,7 +257,7 @@
   void AddToLabel(std::ostream& out, benchmark::State& state) {
     EndpointPairFixture::AddToLabel(out, state);
     out << " writes/iter:"
-        << ((double)stats_.num_writes / (double)state.iterations());
+        << (double)stats_.num_writes / (double)state.iterations();
   }
 
  private:
diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc
index 6550742..73ab9e4 100644
--- a/test/cpp/microbenchmarks/helpers.cc
+++ b/test/cpp/microbenchmarks/helpers.cc
@@ -36,11 +36,11 @@
 void TrackCounters::Finish(benchmark::State &state) {
   std::ostringstream out;
   AddToLabel(out, state);
-  auto label = out.str();
+  std::string label = out.str();
   if (label.length() && label[0] == ' ') {
     label = label.substr(1);
   }
-  state.SetLabel(label);
+  state.SetLabel(label.c_str());
 }
 
 void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) {
diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD
index 6492b63..c6a1fd2 100644
--- a/test/cpp/qps/BUILD
+++ b/test/cpp/qps/BUILD
@@ -29,14 +29,17 @@
 
 licenses(["notice"])  # 3-clause BSD
 
-cc_library(
+load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_cc_library", "grpc_cc_binary")
+
+grpc_cc_library(
     name = "parse_json",
     srcs = ["parse_json.cc"],
     hdrs = ["parse_json.h"],
     deps = ["//:grpc++"],
+    external_deps = ["protobuf"],
 )
 
-cc_library(
+grpc_cc_library(
     name = "qps_worker_impl",
     srcs = [
         "client_async.cc",
@@ -56,7 +59,6 @@
         ":usage_timer",
         "//:grpc",
         "//:grpc++",
-        "//external:gtest",
         "//src/proto/grpc/testing:control_proto",
         "//src/proto/grpc/testing:payloads_proto",
         "//src/proto/grpc/testing:services_proto",
@@ -65,9 +67,12 @@
         "//test/core/util:grpc_test_util",
         "//test/cpp/util:test_util",
     ],
+    external_deps = [
+        "gtest",
+    ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "driver_impl",
     srcs = [
         "driver.cc",
@@ -90,7 +95,7 @@
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "benchmark_config",
     srcs = [
         "benchmark_config.cc",
@@ -102,12 +107,14 @@
         ":driver_impl",
         ":histogram",
         "//:grpc++",
-        "//external:gflags",
         "//src/proto/grpc/testing:control_proto",
     ],
+    external_deps = [
+        "gflags",
+    ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "histogram",
     hdrs = [
         "histogram.h",
@@ -116,13 +123,13 @@
     deps = ["//:gpr"],
 )
 
-cc_library(
+grpc_cc_library(
     name = "interarrival",
     hdrs = ["interarrival.h"],
     deps = ["//:grpc++"],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "json_run_localhost",
     srcs = ["json_run_localhost.cc"],
     deps = [
@@ -133,7 +140,7 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "qps_interarrival_test",
     srcs = ["qps_interarrival_test.cc"],
     deps = [
@@ -142,18 +149,20 @@
     ],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "qps_json_driver",
     srcs = ["qps_json_driver.cc"],
     deps = [
         ":benchmark_config",
         ":driver_impl",
         "//:grpc++",
-        "//external:gflags",
+    ],
+    external_deps = [
+        "gflags",
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "qps_openloop_test",
     srcs = ["qps_openloop_test.cc"],
     deps = [
@@ -163,7 +172,7 @@
     ],
 )
 
-cc_test(
+grpc_cc_test(
     name = "secure_sync_unary_ping_pong_test",
     srcs = ["secure_sync_unary_ping_pong_test.cc"],
     deps = [
@@ -173,14 +182,14 @@
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "usage_timer",
     srcs = ["usage_timer.cc"],
     hdrs = ["usage_timer.h"],
     deps = ["//:gpr"],
 )
 
-cc_binary(
+grpc_cc_binary(
     name = "qps_worker",
     srcs = ["worker.cc"],
     deps = [
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index c3197eb..5ae6b54 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -46,6 +46,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/surface/completion_queue.h"
 #include "src/proto/grpc/testing/payloads.pb.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 
@@ -150,7 +151,8 @@
   Client()
       : timer_(new UsageTimer),
         interarrival_timer_(),
-        started_requests_(false) {
+        started_requests_(false),
+        last_reset_poll_count_(0) {
     gpr_event_init(&start_requests_);
   }
   virtual ~Client() {}
@@ -162,6 +164,8 @@
 
     MaybeStartRequests();
 
+    int cur_poll_count = GetPollCount();
+    int poll_count = cur_poll_count - last_reset_poll_count_;
     if (reset) {
       std::vector<Histogram> to_merge(threads_.size());
       std::vector<StatusHistogram> to_merge_status(threads_.size());
@@ -176,6 +180,7 @@
         MergeStatusHistogram(to_merge_status[i], &statuses);
       }
       timer_result = timer->Mark();
+      last_reset_poll_count_ = cur_poll_count;
     } else {
       // merge snapshots of each thread histogram
       for (size_t i = 0; i < threads_.size(); i++) {
@@ -195,6 +200,7 @@
     stats.set_time_elapsed(timer_result.wall);
     stats.set_time_system(timer_result.system);
     stats.set_time_user(timer_result.user);
+    stats.set_cq_poll_count(poll_count);
     return stats;
   }
 
@@ -209,6 +215,11 @@
     }
   }
 
+  virtual int GetPollCount() {
+    // For sync client.
+    return 0;
+  }
+
  protected:
   bool closed_loop_;
   gpr_atm thread_pool_done_;
@@ -351,6 +362,8 @@
   gpr_event start_requests_;
   bool started_requests_;
 
+  int last_reset_poll_count_;
+
   void MaybeStartRequests() {
     if (!started_requests_) {
       started_requests_ = true;
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 82c3356..6b8f736 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -205,6 +205,14 @@
     }
   }
 
+  int GetPollCount() override {
+    int count = 0;
+    for (auto cq = cli_cqs_.begin(); cq != cli_cqs_.end(); cq++) {
+      count += grpc_get_cq_poll_num((*cq)->cq());
+    }
+    return count;
+  }
+
  protected:
   const int num_async_threads_;
 
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 9075033..f357132 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -48,7 +48,6 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
-#include <gtest/gtest.h>
 
 #include "src/core/lib/profiling/timers.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 74fe366..ace5028 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -112,6 +112,8 @@
 static double WallTime(ClientStats s) { return s.time_elapsed(); }
 static double SystemTime(ClientStats s) { return s.time_system(); }
 static double UserTime(ClientStats s) { return s.time_user(); }
+static double CliPollCount(ClientStats s) { return s.cq_poll_count(); }
+static double SvrPollCount(ServerStats s) { return s.cq_poll_count(); }
 static double ServerWallTime(ServerStats s) { return s.time_elapsed(); }
 static double ServerSystemTime(ServerStats s) { return s.time_system(); }
 static double ServerUserTime(ServerStats s) { return s.time_user(); }
@@ -180,6 +182,11 @@
     result->mutable_summary()->set_failed_requests_per_second(failures /
                                                               time_estimate);
   }
+
+  result->mutable_summary()->set_client_polls_per_request(
+      sum(result->client_stats(), CliPollCount) / histogram.Count());
+  result->mutable_summary()->set_server_polls_per_request(
+      sum(result->server_stats(), SvrPollCount) / histogram.Count());
 }
 
 std::unique_ptr<ScenarioResult> RunScenario(
diff --git a/test/cpp/qps/qps_json_driver.cc b/test/cpp/qps/qps_json_driver.cc
index a906137..f00f771 100644
--- a/test/cpp/qps/qps_json_driver.cc
+++ b/test/cpp/qps/qps_json_driver.cc
@@ -94,6 +94,7 @@
   GetReporter()->ReportLatency(*result);
   GetReporter()->ReportTimes(*result);
   GetReporter()->ReportCpuUsage(*result);
+  GetReporter()->ReportPollCount(*result);
 
   for (int i = 0; *success && i < result->client_success_size(); i++) {
     *success = result->client_success(i);
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index a9130bf..8bb4c9a 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -80,6 +80,12 @@
   }
 }
 
+void CompositeReporter::ReportPollCount(const ScenarioResult& result) {
+  for (size_t i = 0; i < reporters_.size(); ++i) {
+    reporters_[i]->ReportPollCount(result);
+  }
+}
+
 void GprLogReporter::ReportQPS(const ScenarioResult& result) {
   gpr_log(GPR_INFO, "QPS: %.1f", result.summary().qps());
   if (result.summary().failed_requests_per_second() > 0) {
@@ -121,6 +127,13 @@
           result.summary().server_cpu_usage());
 }
 
+void GprLogReporter::ReportPollCount(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "Client Polls per Request: %.2f",
+          result.summary().client_polls_per_request());
+  gpr_log(GPR_INFO, "Server Polls per Request: %.2f",
+          result.summary().server_polls_per_request());
+}
+
 void JsonReporter::ReportQPS(const ScenarioResult& result) {
   grpc::string json_string =
       SerializeJson(result, "type.googleapis.com/grpc.testing.ScenarioResult");
@@ -145,6 +158,10 @@
   // NOP - all reporting is handled by ReportQPS.
 }
 
+void JsonReporter::ReportPollCount(const ScenarioResult& result) {
+  // NOP - all reporting is handled by ReportQPS.
+}
+
 void RpcReporter::ReportQPS(const ScenarioResult& result) {
   grpc::ClientContext context;
   grpc::Status status;
@@ -177,5 +194,9 @@
   // NOP - all reporting is handled by ReportQPS.
 }
 
+void RpcReporter::ReportPollCount(const ScenarioResult& result) {
+  // NOP - all reporting is handled by ReportQPS.
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index 1749be9..621fa7c 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -76,6 +76,9 @@
   /** Reports server cpu usage. */
   virtual void ReportCpuUsage(const ScenarioResult& result) = 0;
 
+  /** Reports client and server poll usage inside completion queue. */
+  virtual void ReportPollCount(const ScenarioResult& result) = 0;
+
  private:
   const string name_;
 };
@@ -93,6 +96,7 @@
   void ReportLatency(const ScenarioResult& result) override;
   void ReportTimes(const ScenarioResult& result) override;
   void ReportCpuUsage(const ScenarioResult& result) override;
+  void ReportPollCount(const ScenarioResult& result) override;
 
  private:
   std::vector<std::unique_ptr<Reporter> > reporters_;
@@ -109,6 +113,7 @@
   void ReportLatency(const ScenarioResult& result) override;
   void ReportTimes(const ScenarioResult& result) override;
   void ReportCpuUsage(const ScenarioResult& result) override;
+  void ReportPollCount(const ScenarioResult& result) override;
 };
 
 /** Dumps the report to a JSON file. */
@@ -123,6 +128,7 @@
   void ReportLatency(const ScenarioResult& result) override;
   void ReportTimes(const ScenarioResult& result) override;
   void ReportCpuUsage(const ScenarioResult& result) override;
+  void ReportPollCount(const ScenarioResult& result) override;
 
   const string report_file_;
 };
@@ -138,6 +144,7 @@
   void ReportLatency(const ScenarioResult& result) override;
   void ReportTimes(const ScenarioResult& result) override;
   void ReportCpuUsage(const ScenarioResult& result) override;
+  void ReportPollCount(const ScenarioResult& result) override;
 
   std::unique_ptr<ReportQpsScenarioService::Stub> stub_;
 };
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 8fbf37a..a03dd1a 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -38,6 +38,7 @@
 #include <grpc/support/cpu.h>
 #include <vector>
 
+#include "src/core/lib/surface/completion_queue.h"
 #include "src/proto/grpc/testing/control.pb.h"
 #include "src/proto/grpc/testing/messages.pb.h"
 #include "test/core/end2end/data/ssl_test_data.h"
@@ -49,7 +50,8 @@
 
 class Server {
  public:
-  explicit Server(const ServerConfig& config) : timer_(new UsageTimer) {
+  explicit Server(const ServerConfig& config)
+      : timer_(new UsageTimer), last_reset_poll_count_(0) {
     cores_ = gpr_cpu_num_cores();
     if (config.port()) {
       port_ = config.port();
@@ -62,10 +64,13 @@
 
   ServerStats Mark(bool reset) {
     UsageTimer::Result timer_result;
+    int cur_poll_count = GetPollCount();
+    int poll_count = cur_poll_count - last_reset_poll_count_;
     if (reset) {
       std::unique_ptr<UsageTimer> timer(new UsageTimer);
       timer.swap(timer_);
       timer_result = timer->Mark();
+      last_reset_poll_count_ = cur_poll_count;
     } else {
       timer_result = timer_->Mark();
     }
@@ -76,6 +81,7 @@
     stats.set_time_user(timer_result.user);
     stats.set_total_cpu_time(timer_result.total_cpu_time);
     stats.set_idle_cpu_time(timer_result.idle_cpu_time);
+    stats.set_cq_poll_count(poll_count);
     return stats;
   }
 
@@ -106,10 +112,16 @@
     }
   }
 
+  virtual int GetPollCount() {
+    // For sync server.
+    return 0;
+  }
+
  private:
   int port_;
   int cores_;
   std::unique_ptr<UsageTimer> timer_;
+  int last_reset_poll_count_;
 };
 
 std::unique_ptr<Server> CreateSynchronousServer(const ServerConfig& config);
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 84f1579..3403ffd 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -186,6 +186,14 @@
     shutdown_thread.join();
   }
 
+  int GetPollCount() override {
+    int count = 0;
+    for (auto cq = srv_cqs_.begin(); cq != srv_cqs_.end(); cq++) {
+      count += grpc_get_cq_poll_num((*cq)->cq());
+    }
+    return count;
+  }
+
  private:
   void ShutdownThreadFunc() {
     // TODO (vpai): Remove this deadline and allow Shutdown to finish properly
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index 9dde22b..453e9b6 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -29,16 +29,20 @@
 
 licenses(["notice"])  # 3-clause BSD
 
+load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_binary")
+
+package(default_visibility = ["//visibility:public"])
+
 # The following builds a shared-object to confirm that grpc++_unsecure
 # builds properly. Build-only is sufficient here
-cc_binary(
+grpc_cc_binary(
     name = "testso.so",
     srcs = [],
     linkshared = 1,
     deps = ["//:grpc++_unsecure"],
 )
 
-cc_library(
+grpc_cc_library(
     name = "test_config",
     srcs = [
         "test_config_cc.cc",
@@ -46,14 +50,15 @@
     hdrs = [
         "test_config.h",
     ],
-    visibility = ["//test:__subpackages__"],
+    external_deps = [
+        "gflags",
+    ],
     deps = [
         "//:gpr",
-        "//external:gflags",
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "grpc++_proto_reflection_desc_db",
     srcs = [
         "proto_reflection_descriptor_database.cc",
@@ -61,14 +66,13 @@
     hdrs = [
         "proto_reflection_descriptor_database.h",
     ],
-    visibility = ["//test:__subpackages__"],
     deps = [
         "//:grpc++_config_proto",
         "//src/proto/grpc/reflection/v1alpha:reflection_proto",
     ],
 )
 
-cc_library(
+grpc_cc_library(
     name = "test_util",
     srcs = [
         "byte_buffer_proto_helper.cc",
@@ -84,12 +88,57 @@
         "subprocess.h",
         "test_credentials_provider.h",
     ],
-    visibility = ["//test:__subpackages__"],
     deps = [
         "//:grpc++",
         "//test/core/end2end:ssl_test_data",
         "//test/core/util:gpr_test_util",
     ],
+    external_deps = [
+        "protobuf",
+    ],
+)
+
+grpc_cc_library(
+    name = "grpc_cli_libs",
+    srcs = [
+        "cli_call.cc",
+        "cli_credentials.cc",
+        "grpc_tool.cc",
+        "proto_file_parser.cc",
+        "service_describer.cc",
+    ],
+    hdrs = [
+        "cli_call.h",
+        "cli_credentials.h",
+        "config_grpc_cli.h",
+        "grpc_tool.h",
+        "proto_file_parser.h",
+        "service_describer.h",
+    ],
+    deps = [
+        "//:grpc++",
+        "//src/proto/grpc/reflection/v1alpha:reflection_proto",
+        ":grpc++_proto_reflection_desc_db",
+    ],
+    external_deps = [
+        "gflags",
+        "protobuf",
+        "protobuf_clib",
+    ],
+)
+
+grpc_cc_library(
+    name = "metrics_server_lib",
+    srcs = [
+        "metrics_server.cc",
+    ],
+    hdrs = [
+        "metrics_server.h",
+    ],
+    deps = [
+        "//src/proto/grpc/testing:metrics_proto",
+        "//:grpc++",
+    ],
 )
 
 cc_test(
diff --git a/test/distrib/csharp/run_distrib_test.bat b/test/distrib/csharp/run_distrib_test.bat
index cb5dd55..aeadef3 100644
--- a/test/distrib/csharp/run_distrib_test.bat
+++ b/test/distrib/csharp/run_distrib_test.bat
@@ -31,7 +31,7 @@
 cd /d %~dp0
 
 @rem extract input artifacts
-powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('../../../input_artifacts/csharp_nugets_windows_dotnetcli.zip', 'TestNugetFeed');"
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('../../../../input_artifacts/csharp_nugets_windows_dotnetcli.zip', 'TestNugetFeed');"
 
 update_version.sh auto
 
diff --git a/tools/dockerfile/push_testing_images.sh b/tools/dockerfile/push_testing_images.sh
index 973e045..16e43a1 100755
--- a/tools/dockerfile/push_testing_images.sh
+++ b/tools/dockerfile/push_testing_images.sh
@@ -44,7 +44,7 @@
 
 DOCKERHUB_ORGANIZATION=grpctesting
 
-for DOCKERFILE_DIR in tools/dockerfile/test/*
+for DOCKERFILE_DIR in tools/dockerfile/test/* tools/dockerfile/grpc_artifact_*
 do
   # Generate image name based on Dockerfile checksum. That works well as long
   # as can count on dockerfiles being written in a way that changing the logical 
diff --git a/tools/dockerfile/test/bazel/Dockerfile b/tools/dockerfile/test/bazel/Dockerfile
index 6ea8ef3..c562704 100644
--- a/tools/dockerfile/test/bazel/Dockerfile
+++ b/tools/dockerfile/test/bazel/Dockerfile
@@ -27,46 +27,22 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-FROM ubuntu:15.10
+FROM gcr.io/oss-fuzz-base/base-builder
 
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
+# Install basic packages and Bazel dependencies.
+RUN apt-get update && apt-get install -y software-properties-common python-software-properties
+RUN add-apt-repository ppa:webupd8team/java
+RUN apt-get update && apt-get -y install \
   autoconf \
-  autotools-dev \
   build-essential \
-  bzip2 \
-  ccache \
   curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
   libtool \
   make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-#================
-# Build profiling
-RUN apt-get update && apt-get install -y time && apt-get clean
-
+  openjdk-8-jdk \
+  vim
 
 #========================
 # Bazel installation
-RUN apt-get install -y software-properties-common g++
 RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" > /etc/apt/sources.list.d/bazel.list
 RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
 RUN apt-get -y update
diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
index f946875..b13157f 100644
--- a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -27,7 +27,7 @@
 # (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 alpine:3.3
+FROM alpine:3.5
 
 # Install Git and basic packages.
 RUN apk update && apk add \
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 1d2aa95..b7531bc 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -792,6 +792,7 @@
 doc/status_ordering.md \
 doc/statuscodes.md \
 doc/stress_test_framework.md \
+doc/unit_testing.md \
 doc/wait-for-ready.md \
 include/grpc++/alarm.h \
 include/grpc++/channel.h \
@@ -897,7 +898,8 @@
 include/grpc/load_reporting.h \
 include/grpc/slice.h \
 include/grpc/slice_buffer.h \
-include/grpc/status.h
+include/grpc/status.h \
+include/grpc/support/workaround_list.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 3214179..c8ebb0d 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -792,6 +792,7 @@
 doc/status_ordering.md \
 doc/statuscodes.md \
 doc/stress_test_framework.md \
+doc/unit_testing.md \
 doc/wait-for-ready.md \
 include/grpc++/alarm.h \
 include/grpc++/channel.h \
@@ -899,6 +900,7 @@
 include/grpc/slice.h \
 include/grpc/slice_buffer.h \
 include/grpc/status.h \
+include/grpc/support/workaround_list.h \
 src/core/lib/channel/channel_args.c \
 src/core/lib/channel/channel_args.h \
 src/core/lib/channel/channel_stack.c \
@@ -953,6 +955,7 @@
 src/core/lib/iomgr/ev_poll_posix.h \
 src/core/lib/iomgr/ev_posix.c \
 src/core/lib/iomgr/ev_posix.h \
+src/core/lib/iomgr/ev_windows.c \
 src/core/lib/iomgr/exec_ctx.c \
 src/core/lib/iomgr/exec_ctx.h \
 src/core/lib/iomgr/executor.c \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index c3bfc6c..74e76bf 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -792,6 +792,7 @@
 doc/status_ordering.md \
 doc/statuscodes.md \
 doc/stress_test_framework.md \
+doc/unit_testing.md \
 doc/wait-for-ready.md \
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
@@ -860,7 +861,8 @@
 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/support/useful.h \
+include/grpc/support/workaround_list.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 097cbde..d5eeebe 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -792,6 +792,7 @@
 doc/status_ordering.md \
 doc/statuscodes.md \
 doc/stress_test_framework.md \
+doc/unit_testing.md \
 doc/wait-for-ready.md \
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
@@ -861,6 +862,7 @@
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
 include/grpc/support/useful.h \
+include/grpc/support/workaround_list.h \
 src/core/README.md \
 src/core/ext/README.md \
 src/core/ext/census/README.md \
@@ -975,6 +977,10 @@
 src/core/ext/filters/max_age/max_age_filter.h \
 src/core/ext/filters/message_size/message_size_filter.c \
 src/core/ext/filters/message_size/message_size_filter.h \
+src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c \
+src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h \
+src/core/ext/filters/workarounds/workaround_utils.c \
+src/core/ext/filters/workarounds/workaround_utils.h \
 src/core/ext/transport/README.md \
 src/core/ext/transport/chttp2/README.md \
 src/core/ext/transport/chttp2/alpn/alpn.c \
@@ -1092,6 +1098,7 @@
 src/core/lib/iomgr/ev_poll_posix.h \
 src/core/lib/iomgr/ev_posix.c \
 src/core/lib/iomgr/ev_posix.h \
+src/core/lib/iomgr/ev_windows.c \
 src/core/lib/iomgr/exec_ctx.c \
 src/core/lib/iomgr/exec_ctx.h \
 src/core/lib/iomgr/executor.c \
diff --git a/tools/gce/create_linux_worker.sh b/tools/gce/create_linux_worker.sh
index 322a592c..b934f22 100755
--- a/tools/gce/create_linux_worker.sh
+++ b/tools/gce/create_linux_worker.sh
@@ -45,7 +45,8 @@
     --machine-type n1-standard-16 \
     --image=ubuntu-1510 \
     --image-project=grpc-testing \
-    --boot-disk-size 1000
+    --boot-disk-size 1000 \
+    --scopes https://www.googleapis.com/auth/bigquery
 
 echo 'Created GCE instance, waiting 60 seconds for it to come online.'
 sleep 60
diff --git a/tools/grpcz/census.proto b/tools/grpcz/census.proto
deleted file mode 100644
index d1ff694..0000000
--- a/tools/grpcz/census.proto
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright 2017, Google Inc.
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//     http://www.apache.org/licenses/LICENSE-2.0
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//TODO(ericgribkoff) Depend on this directly from the instrumentation-proto
-//repository.
-
-syntax = "proto3";
-
-package google.instrumentation;
-
-option java_package = "com.google.instrumentation.stats.proto";
-option java_outer_classname = "CensusProto";
-
-// All the census protos.
-//
-// Nomenclature notes:
-//   * Capitalized names below (like View) are protos.
-//   * Protos which describe types are named with a Descriptor suffix (e.g.
-//     MesurementDescriptor).
-//
-// Census lets you define the type and description of the data being measured
-// (e.g. the latency of an RPC or the number of CPU cycles spent on an
-// operation using MeasurementDescriptor. As individual measurements (a double
-// value) for are recorded, they are aggregated together into an
-// Aggregation. There are two Aggregation types available: Distribution
-// (describes the distribution of all measurements, possibly with a histogram)
-// and IntervalStats (the count and mean of measurements across specified time
-// periods). An Aggregation is described by an AggregationDescriptor.
-//
-// You can define how your measurements (described by a MeasurementDescriptor)
-// are broken down by Tag values and which Aggregations to use through a
-// ViewDescriptor. The output (all measurements broken down by tag values into
-// specific Aggregations) is called a View.
-
-
-// The following two types are copied from
-// google/protobuf/{duration,timestamp}.proto. Ideally, we would be able to
-// import them, but this causes compilation issues on C-based systems
-// (e.g. https://koti.kapsi.fi/jpa/nanopb/), which cannot process the C++
-// headers generated from the standard protobuf distribution. See the relevant
-// proto files for full documentation of these types.
-
-message Duration {
-  // Signed seconds of the span of time. Must be from -315,576,000,000
-  // to +315,576,000,000 inclusive.
-  int64 seconds = 1;
-
-  // Signed fractions of a second at nanosecond resolution of the span
-  // of time. Durations less than one second are represented with a 0
-  // `seconds` field and a positive or negative `nanos` field. For durations
-  // of one second or more, a non-zero value for the `nanos` field must be
-  // of the same sign as the `seconds` field. Must be from -999,999,999
-  // to +999,999,999 inclusive.
-  int32 nanos = 2;
-}
-
-message Timestamp {
-  // Represents seconds of UTC time since Unix epoch
-  // 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
-  // 9999-12-31T23:59:59Z inclusive.
-  int64 seconds = 1;
-
-  // Non-negative fractions of a second at nanosecond resolution. Negative
-  // second values with fractions must still have non-negative nanos values
-  // that count forward in time. Must be from 0 to 999,999,999
-  // inclusive.
-  int32 nanos = 2;
-}
-
-// MeasurementDescriptor describes a data point (measurement) type.
-message MeasurementDescriptor {
-  // A descriptive name, e.g. rpc_latency, cpu. Must be unique.
-  string name = 1;
-
-  // 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?
-  enum BasicUnit {
-    UNKNOWN = 0;    // Implementations should not use this
-    SCALAR = 1;     // Dimensionless
-    BITS = 2;       // A single bit
-    BYTES = 3;      // An 8-bit byte
-    SECONDS = 4;    // S.I. unit
-    CORES = 5;      // CPU core usage
-    MAX_UNITS = 6;  // Last defined value; implementations should only use
-                    // this for validation.
-  }
-
-  // MeasurementUnit lets you build compound units of the form
-  //   10^n * (A * B * ...) / (X * Y * ...),
-  // where the elements in the numerator and denominator are all BasicUnits.  A
-  // MeasurementUnit must have at least one BasicUnit in its numerator.
-  //
-  // To specify multiplication in the numerator or denominator, simply specify
-  // multiple numerator or denominator fields.  For example:
-  //
-  // - byte-seconds (i.e. bytes * seconds):
-  //     numerator: BYTES
-  //     numerator: SECS
-  //
-  // - events/sec^2 (i.e. rate of change of events/sec):
-  //     numerator: SCALAR
-  //     denominator: SECS
-  //     denominator: SECS
-  //
-  // To specify multiples (in power of 10) of units, specify a non-zero
-  // 'power10' value, for example:
-  //
-  // - MB/s (i.e. megabytes / s):
-  //     power10: 6
-  //     numerator: BYTES
-  //     denominator: SECS
-  //
-  // - nanoseconds
-  //     power10: -9
-  //     numerator: SECS
-  message MeasurementUnit {
-    int32 power10 = 1;
-    repeated BasicUnit numerators = 2;
-    repeated BasicUnit denominators = 3;
-  }
-
-  // The units used by this type of measurement.
-  MeasurementUnit unit = 3;
-}
-
-// An aggregation summarizes a series of individual measurements. There are
-// two types of aggregation (IntervalAggregation and DistributionAggregation),
-// unique types of each can be set using descriptors for each.
-
-// DistributionAggregation contains summary statistics for a population of
-// values and, optionally, a histogram representing the distribution of those
-// values across a specified set of histogram buckets, as defined in
-// DistributionAggregationDescriptor.bucket_bounds.
-//
-// 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
-// will render the `mean` field meaningless.
-message DistributionAggregation {
-  // The number of values in the population. Must be non-negative.
-  int64 count = 1;
-
-  // The arithmetic mean of the values in the population. If `count` is zero
-  // then this field must be zero.
-  double mean = 2;
-
-  // The sum of the values in the population.  If `count` is zero then this
-  // field must be zero.
-  double sum = 3;
-
-  // Describes a range of population values.
-  message Range {
-    // The minimum of the population values.
-    double min = 1;
-    // The maximum of the population values.
-    double max = 2;
-  }
-
-  // The range of the population values. If `count` is zero, this field will not
-  // be defined.
-  Range range = 4;
-
-  // A Distribution may optionally contain a histogram of the values in the
-  // population. The histogram is given in `bucket_count` as counts of values
-  // that fall into one of a sequence of non-overlapping buckets, as described
-  // by `DistributionAggregationDescriptor.bucket_boundaries`. The sum of the
-  // values in `bucket_counts` must equal the value in `count`.
-  //
-  // Bucket counts are given in order under the numbering scheme described
-  // above (the underflow bucket has number 0; the finite buckets, if any,
-  // have numbers 1 through N-2; the overflow bucket has number N-1).
-  //
-  // The size of `bucket_count` must be no greater than N as defined in
-  // `bucket_boundaries`.
-  //
-  // Any suffix of trailing zero bucket_count fields may be omitted.
-  repeated int64 bucket_counts = 5;
-
-  // Tags associated with this DistributionAggregation. These will be filled
-  // in based on the View specification.
-  repeated Tag tags = 6;
-}
-
-message DistributionAggregationDescriptor {
-  // A Distribution may optionally contain a histogram of the values in the
-  // population. The bucket boundaries for that histogram are described by
-  // `bucket_bounds`. This defines `size(bucket_bounds) + 1` (= N)
-  // buckets. The boundaries for bucket index i are:
-  //
-  // [-infinity, bucket_bounds[i]) for i == 0
-  // [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-2
-  // [bucket_bounds[i-1], +infinity) for i == N-1
-  //
-  // i.e. an underflow bucket (number 0), zero or more finite buckets (1
-  // through N - 2, and an overflow bucket (N - 1), with inclusive lower
-  // bounds and exclusive upper bounds.
-  //
-  // If `bucket_bounds` has no elements (zero size), then there is no
-  // histogram associated with the Distribution. If `bucket_bounds` has only
-  // one element, there are no finite buckets, and that single element is the
-  // common boundary of the overflow and underflow buckets. The values must
-  // be monotonically increasing.
-  repeated double bucket_bounds = 1;
-}
-
-// An IntervalAggreation records summary stats over various time
-// windows. These stats are approximate, with the degree of accuracy
-// controlled by setting the n_sub_intervals parameter in the
-// IntervalAggregationDescriptor.
-message IntervalAggregation {
-  // Summary statistic over a single time interval.
-  message Interval {
-    // The interval duration. Must be positive.
-    Duration interval_size = 1;
-    // Approximate number of measurements recorded in this interval.
-    double count = 2;
-    // The cumulative sum of measurements in this interval.
-    double sum = 3;
-  }
-
-  // Full set of intervals for this aggregation.
-  repeated Interval intervals = 1;
-
-  // Tags associated with this IntervalAggregation. These will be filled in
-  // based on the View specification.
-  repeated Tag tags = 2;
-}
-
-// An IntervalAggreationDescriptor specifies time intervals for an
-// IntervalAggregation.
-message IntervalAggregationDescriptor {
-  // Number of internal sub-intervals to use when collecting stats for each
-  // interval. The max error in interval measurements will be approximately
-  // 1/n_sub_intervals (although in practice, this will only be approached in
-  // the presence of very large and bursty workload changes), and underlying
-  // memory usage will be roughly proportional to the value of this
-  // field. Must be in the range [2, 20]. A value of 5 will be used if this is
-  // unspecified.
-  int32 n_sub_intervals = 1;
-
-  // The size of each interval, as a time duration. Must have at least one
-  // element.
-  repeated Duration interval_sizes = 2;
-}
-
-// A Tag: key-value pair.
-message Tag {
-  string key = 1;
-  string value = 2;
-}
-
-// A ViewDescriptor specifies an AggregationDescriptor and a set of tag
-// keys. Views instantiated from this descriptor will contain Aggregations
-// broken down by the unique set of matching tag values for each measurement.
-message ViewDescriptor {
-  // Name of view. Must be unique.
-  string name = 1;
-
-  // More detailed description, for documentation purposes.
-  string description = 2;
-
-  // Name of a MeasurementDescriptor to be used for this view.
-  string measurement_descriptor_name = 3;
-
-  // Aggregation type to associate with View.
-  oneof aggregation {
-    IntervalAggregationDescriptor interval_aggregation = 4;
-    DistributionAggregationDescriptor distribution_aggregation = 5;
-  }
-
-  // Tag keys to match with a given measurement. If no keys are specified,
-  // then all stats are recorded. Keys must be unique.
-  repeated string tag_keys = 6;
-}
-
-// DistributionView contains all aggregations for a view specified using a
-// DistributionAggregationDescriptor.
-message DistributionView {
-  // Aggregations - each will have a unique set of tag values for the tag_keys
-  // associated with the corresponding View.
-  repeated DistributionAggregation aggregations = 1;
-
-  // Start and end timestamps over which aggregations was accumulated.
-  Timestamp start = 2;
-  Timestamp end = 3;
-}
-
-// IntervalView contains all aggregations for a view specified using a
-// IntervalAggregationDescriptor.
-message IntervalView {
-  // Aggregations - each will have a unique set of tag values for the tag_keys
-  // associated with the corresponding View.
-  repeated IntervalAggregation aggregations = 1;
-}
-
-// A View contains the aggregations based on a ViewDescriptor.
-message View {
-  // ViewDescriptor name associated with this set of View.
-  string view_name = 1;
-
-  oneof view {
-    DistributionView distribution_view = 2;
-    IntervalView interval_view = 3;
-  }
-}
diff --git a/tools/grpcz/grpcz_client.cc b/tools/grpcz/grpcz_client.cc
deleted file mode 100644
index a5e66f7..0000000
--- a/tools/grpcz/grpcz_client.cc
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- *
- * Copyright 2017, 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>
-
-#include <google/protobuf/util/json_util.h>
-#include <grpc++/grpc++.h>
-#include <grpc/support/log.h>
-
-#include "gflags/gflags.h"
-/* #include "mongoose.h" */
-
-// TODO (makdharma): remove local copies of these protos
-#include "tools/grpcz/census.grpc.pb.h"
-#include "tools/grpcz/monitoring.grpc.pb.h"
-
-DEFINE_string(
-    grpcz_server, "127.0.0.1:8080",
-    "Unix domain socket path (e.g. unix://tmp/grpcz.sock) or IP address"
-    "(host:port) where grpcz server is running.");
-DEFINE_string(http_port, "8000",
-              "Port id for accessing the HTTP server that renders /grpcz page");
-DEFINE_bool(print_to_console, false,
-            "print the JSON retreived from grpcz server and quit");
-
-using grpc::Channel;
-using grpc::ClientContext;
-using grpc::Status;
-
-using ::grpc::instrumentation::v1alpha::CanonicalRpcStats;
-using ::grpc::instrumentation::v1alpha::Monitoring;
-
-static const std::string static_html_header =
-    "<!DOCTYPE html> <html> <head> <style> \
-table { border-collapse: collapse; width: 100%; } \
-table, td, th { border: 1px solid black; } \
-</style> </head> <body>\
-<div id='stats' data-stats='";
-
-static const std::string static_html_footer =
-    "' class='hidden'></div>\
-<h1>GRPCZ Statistics</h1> <div id='table'> </div> \
-<script> \
-  var canonical_stats = JSON.parse(\
-            document.getElementById('stats').getAttribute('data-stats')); \
-  var table = document.createElement('table'); \
-  if (canonical_stats['Error Message'] != undefined) { \
-     document.getElementById('table').innerHTML = canonical_stats['Error Message']; } \
-  else {\
-  for (var key in canonical_stats) { \
-    name = canonical_stats[key]['view']['viewName']; \
-    distribution = canonical_stats[key]['view']['distributionView']; \
-    interval = canonical_stats[key]['view']['intervalView']; \
-    value = (interval == undefined) ? \
-      JSON.stringify(distribution, null, ' ') : \
-      JSON.stringify(interval, null, ' '); \
-    var row = table.insertRow(-1); \
-    var col1 = row.insertCell(0); \
-    var col2 = row.insertCell(1); \
-    col1.innerHTML = name; \
-    col2.innerHTML = '<pre>' + value + '</pre>'; \
-  } \
-  document.getElementById('table').appendChild(table); \
-  }\
-</script> </body> </html>";
-
-class GrpczClient {
- public:
-  GrpczClient(std::shared_ptr<Channel> channel)
-      : stub_(Monitoring::NewStub(channel)) {}
-
-  std::string GetStatsAsJson() {
-    const ::google::protobuf::Empty request;
-    CanonicalRpcStats reply;
-    ClientContext context;
-    Status status = stub_->GetCanonicalRpcStats(&context, request, &reply);
-
-    if (status.ok()) {
-      std::string json_str;
-      ::google::protobuf::util::MessageToJsonString(reply, &json_str);
-      return json_str;
-    } else {
-      static const std::string error_message_json =
-          "{\"Error Message\":\"" + status.error_message() + "\"}";
-      gpr_log(GPR_DEBUG, "%d: %s", status.error_code(),
-              status.error_message().c_str());
-      return error_message_json;
-    }
-  }
-
- private:
-  std::unique_ptr<Monitoring::Stub> stub_;
-};
-
-std::unique_ptr<GrpczClient> g_grpcz_client;
-/*
-static struct mg_serve_http_opts s_http_server_opts;
-
-static void ev_handler(struct mg_connection *nc, int ev, void *p) {
-  if (ev == MG_EV_HTTP_REQUEST) {
-    mg_serve_http(nc, (struct http_message *)p, s_http_server_opts);
-  }
-}
-
-static void grpcz_handler(struct mg_connection *nc, int ev, void *ev_data) {
-  (void)ev;
-  (void)ev_data;
-  gpr_log(GPR_INFO, "fetching grpcz stats from %s", FLAGS_grpcz_server.c_str());
-  std::string json_str = g_grpcz_client->GetStatsAsJson();
-  std::string rendered_html =
-      static_html_header + json_str + static_html_footer;
-  mg_printf(nc, "HTTP/1.0 200 OK\r\n\r\n%s", rendered_html.c_str());
-  nc->flags |= MG_F_SEND_AND_CLOSE;
-}
-*/
-
-int main(int argc, char **argv) {
-  gflags::ParseCommandLineFlags(&argc, &argv, true);
-
-  // Create a client
-  g_grpcz_client.reset(new GrpczClient(grpc::CreateChannel(
-      FLAGS_grpcz_server, grpc::InsecureChannelCredentials())));
-  if (FLAGS_print_to_console) {
-    // using GPR_ERROR since this is the default verbosity. _DEBUG or _INFO
-    // won't print unless GRPC_VERBOSITY env var is set appropriately, which
-    // might confuse users of this utility.
-    gpr_log(GPR_ERROR, "%s\n", g_grpcz_client->GetStatsAsJson().c_str());
-    return 0;
-  }
-
-  /*
-  // Set up a mongoose webserver handler
-  struct mg_mgr mgr;
-  mg_mgr_init(&mgr, NULL);
-  gpr_log(GPR_INFO, "Starting grpcz web server on port %s\n",
-          FLAGS_http_port.c_str());
-
-  struct mg_connection *nc = mg_bind(&mgr, FLAGS_http_port.c_str(), ev_handler);
-  if (nc == NULL) {
-    gpr_log(GPR_ERROR, "Failed to create listener on port %s\n",
-            FLAGS_http_port.c_str());
-    return -1;
-  }
-  mg_register_http_endpoint(nc, "/grpcz", grpcz_handler);
-  mg_set_protocol_http_websocket(nc);
-
-  // Poll in a loop and serve /grpcz pages
-  for (;;) {
-    static const int k_sleep_millis = 100;
-    mg_mgr_poll(&mgr, k_sleep_millis);
-  }
-  mg_mgr_free(&mgr);
-  */
-  return 0;
-}
diff --git a/tools/grpcz/monitoring.proto b/tools/grpcz/monitoring.proto
deleted file mode 100644
index fefcd7d..0000000
--- a/tools/grpcz/monitoring.proto
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2017, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// This file defines an interface for exporting monitoring information
-// out of gRPC servers.
-syntax = "proto3";
-
-// TODO(ericgribkoff) Figure out how to manage the external Census proto
-// dependency.
-import "tools/grpcz/census.proto";
-import "google/protobuf/any.proto";
-import "google/protobuf/empty.proto";
-
-package grpc.instrumentation.v1alpha;
-
-option java_multiple_files = true;
-option java_package = "io.grpc.instrumentation.v1alpha";
-option java_outer_classname = "MonitoringProto";
-
-service Monitoring {
-  // Return canonical RPC stats
-  rpc GetCanonicalRpcStats(google.protobuf.Empty) returns (CanonicalRpcStats) {
-  }
-
-  // Query the server for specific stats
-  rpc GetStats(StatsRequest) returns (StatsResponse) {
-  }
-
-  // Request the server to stream back snapshots of the requested stats
-  rpc WatchStats(StatsRequest) returns (stream StatsResponse) {
-  }
-
-
-  // Return request traces.
-  rpc GetRequestTraces(TraceRequest) returns(TraceResponse) {
-  // TODO(aveitch): Please define the messages here
-  }
-
-  // Return application-defined groups of monitoring data.
-  // This is a low level facility to allow extension of the monitoring API to
-  // application-specific monitoring data. Frameworks may use this to define
-  // additional groups of monitoring data made available by servers.
-  rpc GetCustomMonitoringData(MonitoringDataGroup)
-    returns (CustomMonitoringData) {
-  }
-
-}
-
-// Canonical RPC stats exported by gRPC.
-message CanonicalRpcStats {
-  StatsResponse rpc_client_errors = 1;
-  StatsResponse rpc_client_completed_rpcs = 2;
-  StatsResponse rpc_client_started_rpcs = 3;
-  StatsResponse rpc_client_elapsed_time = 4;
-  StatsResponse rpc_client_server_elapsed_time = 5;
-  StatsResponse rpc_client_request_bytes = 6;
-  StatsResponse rpc_client_response_bytes = 7;
-  StatsResponse rpc_client_request_count = 8;
-  StatsResponse rpc_client_response_count = 9;
-  StatsResponse rpc_server_errors = 10;
-  StatsResponse rpc_server_completed_rpcs = 11;
-  StatsResponse rpc_server_server_elapsed_time = 12;
-  StatsResponse rpc_server_request_bytes = 13;
-  StatsResponse rpc_server_response_bytes = 14;
-  StatsResponse rpc_server_request_count = 15;
-  StatsResponse rpc_server_response_count = 16;
-  StatsResponse rpc_server_elapsed_time = 17;
-  //TODO(ericgribkoff) Add minute-hour interval stats.
-}
-
-// This message is sent when requesting a set of stats (Census Views) from
-// a client system, as part of the MonitoringService API's.
-message StatsRequest {
-  // An optional set of ViewDescriptor names. Only Views using these
-  // descriptors will be sent back in the response. If no names are provided,
-  // then all Views present in the client system will be included in every
-  // response. If measurement_names is also provided, then Views matching the
-  // intersection of the two are returned.
-  // TODO(aveitch): Consider making this a list of regexes or prefix matches in
-  // the future.
-  repeated string view_names = 1;
-
-  // An optional set of MeasurementDescriptor names. Only Views using these
-  // descriptors will be sent back in the response. If no names are provided,
-  // then all Views present in the client system will be included in every
-  // response. If view_names is also provided, then Views matching the
-  // intersection of the two are returned.
-  // TODO(aveitch): Consider making this a list of regexes or prefix matches in
-  // the future.
-  repeated string measurement_names = 2;
-
-  // By default, the MeasurementDescriptors and ViewDescriptors corresponding to
-  // the Views that are returned in a StatsResponse will be included in the
-  // first such response. Set this to true to have them not sent.
-  bool dont_include_descriptors_in_first_response = 3;
-}
-
-// This message contains all information relevant to a single View. It is the
-// return type for GetStats and WatchStats, and used in CanonicalRpcStats.
-message StatsResponse {
-  // A StatsResponse can optionally contain the MeasurementDescriptor and
-  // ViewDescriptor for the View. These will be sent in the first WatchStats
-  // response, or all GetStats and GetCanonicalRpcStats responses. These will
-  // not be set for {Get,Watch}Stats if
-  // dont_include_descriptors_in_first_response is set to true in the
-  // StatsRequest.
-  google.instrumentation.MeasurementDescriptor measurement_descriptor = 1;
-  google.instrumentation.ViewDescriptor view_descriptor = 2;
-
-  // The View data.
-  google.instrumentation.View view = 3;
-}
-
-message TraceRequest {
-  // TODO(aveitch): Complete definition of this type
-}
-
-message TraceResponse {
-  // TODO(aveitch): Complete definition of this type
-}
-
-message MonitoringDataGroup {
-  string name = 1;  // name of a group of monitoring data
-}
-
-// The wrapper for custom monitoring data.
-message CustomMonitoringData {
-  // can be any application specific monitoring data
-  google.protobuf.Any contents = 1;
-}
diff --git a/tools/internal_ci/helper_scripts/prepare_build_linux_rc b/tools/internal_ci/helper_scripts/prepare_build_linux_rc
index c8cb5a0..7f6e093 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_linux_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_linux_rc
@@ -33,6 +33,10 @@
 # Need to increase open files limit for c tests
 ulimit -n 32768
 
+# Move docker's storage location to scratch disk so we don't run out of space.
+echo 'DOCKER_OPTS="${DOCKER_OPTS} --graph=/tmpfs/docker"' | sudo tee --append /etc/default/docker
+sudo service docker restart
+
 # Download Docker images from DockerHub
 export DOCKERHUB_ORGANIZATION=grpctesting
 
diff --git a/tools/grpcz/BUILD b/tools/internal_ci/linux/grpc_build_artifacts.cfg
similarity index 67%
copy from tools/grpcz/BUILD
copy to tools/internal_ci/linux/grpc_build_artifacts.cfg
index cc887a5..eef969b 100644
--- a/tools/grpcz/BUILD
+++ b/tools/internal_ci/linux/grpc_build_artifacts.cfg
@@ -27,37 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-licenses(["notice"])  # 3-clause BSD
+# Config file for the internal CI (in protobuf text format)
 
-package(default_visibility = ["//visibility:public"])
-
-load("//:bazel/grpc_build_system.bzl", "grpc_proto_library")
-
-grpc_proto_library(
-    name = "monitoring_proto",
-    srcs = [
-        "monitoring.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-    deps = [
-        ":census_proto",
-    ],
-)
-
-grpc_proto_library(
-    name = "census_proto",
-    srcs = [
-        "census.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-)
-
-cc_binary(
-    name = "grpcz_client",
-    srcs = ["grpcz_client.cc"],
-    deps = [
-        "monitoring_proto",
-        "//external:gflags",
-        "@mongoose_repo//:mongoose_lib",
-    ],
-)
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_build_artifacts.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/grpcz/BUILD b/tools/internal_ci/linux/grpc_build_artifacts.sh
old mode 100644
new mode 100755
similarity index 67%
copy from tools/grpcz/BUILD
copy to tools/internal_ci/linux/grpc_build_artifacts.sh
index cc887a5..1b12be1
--- a/tools/grpcz/BUILD
+++ b/tools/internal_ci/linux/grpc_build_artifacts.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
 # Copyright 2017, Google Inc.
 # All rights reserved.
 #
@@ -27,37 +28,11 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-licenses(["notice"])  # 3-clause BSD
+set -ex
 
-package(default_visibility = ["//visibility:public"])
+# change to grpc repo root
+cd $(dirname $0)/../../..
 
-load("//:bazel/grpc_build_system.bzl", "grpc_proto_library")
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
 
-grpc_proto_library(
-    name = "monitoring_proto",
-    srcs = [
-        "monitoring.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-    deps = [
-        ":census_proto",
-    ],
-)
-
-grpc_proto_library(
-    name = "census_proto",
-    srcs = [
-        "census.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-)
-
-cc_binary(
-    name = "grpcz_client",
-    srcs = ["grpcz_client.cc"],
-    deps = [
-        "monitoring_proto",
-        "//external:gflags",
-        "@mongoose_repo//:mongoose_lib",
-    ],
-)
+tools/run_tests/task_runner.py -f artifact linux
diff --git a/tools/grpcz/BUILD b/tools/internal_ci/macos/grpc_build_artifacts.cfg
similarity index 67%
copy from tools/grpcz/BUILD
copy to tools/internal_ci/macos/grpc_build_artifacts.cfg
index cc887a5..4d25069 100644
--- a/tools/grpcz/BUILD
+++ b/tools/internal_ci/macos/grpc_build_artifacts.cfg
@@ -27,37 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-licenses(["notice"])  # 3-clause BSD
+# Config file for the internal CI (in protobuf text format)
 
-package(default_visibility = ["//visibility:public"])
-
-load("//:bazel/grpc_build_system.bzl", "grpc_proto_library")
-
-grpc_proto_library(
-    name = "monitoring_proto",
-    srcs = [
-        "monitoring.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-    deps = [
-        ":census_proto",
-    ],
-)
-
-grpc_proto_library(
-    name = "census_proto",
-    srcs = [
-        "census.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-)
-
-cc_binary(
-    name = "grpcz_client",
-    srcs = ["grpcz_client.cc"],
-    deps = [
-        "monitoring_proto",
-        "//external:gflags",
-        "@mongoose_repo//:mongoose_lib",
-    ],
-)
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/macos/grpc_build_artifacts.sh"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/grpcz/BUILD b/tools/internal_ci/macos/grpc_build_artifacts.sh
old mode 100644
new mode 100755
similarity index 67%
copy from tools/grpcz/BUILD
copy to tools/internal_ci/macos/grpc_build_artifacts.sh
index cc887a5..b4c118f
--- a/tools/grpcz/BUILD
+++ b/tools/internal_ci/macos/grpc_build_artifacts.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
 # Copyright 2017, Google Inc.
 # All rights reserved.
 #
@@ -27,37 +28,11 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-licenses(["notice"])  # 3-clause BSD
+set -ex
 
-package(default_visibility = ["//visibility:public"])
+# change to grpc repo root
+cd $(dirname $0)/../../..
 
-load("//:bazel/grpc_build_system.bzl", "grpc_proto_library")
+git submodule update --init
 
-grpc_proto_library(
-    name = "monitoring_proto",
-    srcs = [
-        "monitoring.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-    deps = [
-        ":census_proto",
-    ],
-)
-
-grpc_proto_library(
-    name = "census_proto",
-    srcs = [
-        "census.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-)
-
-cc_binary(
-    name = "grpcz_client",
-    srcs = ["grpcz_client.cc"],
-    deps = [
-        "monitoring_proto",
-        "//external:gflags",
-        "@mongoose_repo//:mongoose_lib",
-    ],
-)
+tools/run_tests/task_runner.py -f artifact macos
diff --git a/tools/internal_ci/windows/grpc_build_artifacts.bat b/tools/internal_ci/windows/grpc_build_artifacts.bat
new file mode 100644
index 0000000..648f038
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_build_artifacts.bat
@@ -0,0 +1,43 @@
+@rem Copyright 2017, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem     * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem     * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem     * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+@rem make sure msys binaries are preferred over cygwin binaries
+@rem set path to python 2.7
+set PATH=C:\tools\msys64\usr\bin;C:\Python27;%PATH%
+
+@rem enter repo root
+cd /d %~dp0\..\..\..
+
+git submodule update --init
+
+python tools/run_tests/task_runner.py -f artifact windows || goto :error
+goto :EOF
+
+:error
+exit /b %errorlevel%
diff --git a/tools/grpcz/BUILD b/tools/internal_ci/windows/grpc_build_artifacts.cfg
similarity index 67%
rename from tools/grpcz/BUILD
rename to tools/internal_ci/windows/grpc_build_artifacts.cfg
index cc887a5..8951181 100644
--- a/tools/grpcz/BUILD
+++ b/tools/internal_ci/windows/grpc_build_artifacts.cfg
@@ -27,37 +27,14 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-licenses(["notice"])  # 3-clause BSD
+# Config file for the internal CI (in protobuf text format)
 
-package(default_visibility = ["//visibility:public"])
-
-load("//:bazel/grpc_build_system.bzl", "grpc_proto_library")
-
-grpc_proto_library(
-    name = "monitoring_proto",
-    srcs = [
-        "monitoring.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-    deps = [
-        ":census_proto",
-    ],
-)
-
-grpc_proto_library(
-    name = "census_proto",
-    srcs = [
-        "census.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-)
-
-cc_binary(
-    name = "grpcz_client",
-    srcs = ["grpcz_client.cc"],
-    deps = [
-        "monitoring_proto",
-        "//external:gflags",
-        "@mongoose_repo//:mongoose_lib",
-    ],
-)
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_build_artifacts.bat"
+timeout_mins: 120
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/artifacts/**"
+  }
+}
diff --git a/tools/run_tests/artifacts/artifact_targets.py b/tools/run_tests/artifacts/artifact_targets.py
index c90da06..5a71b96 100644
--- a/tools/run_tests/artifacts/artifact_targets.py
+++ b/tools/run_tests/artifacts/artifact_targets.py
@@ -45,6 +45,7 @@
   """Creates jobspec for a task running under docker."""
   environ = environ.copy()
   environ['RUN_COMMAND'] = shell_command
+  environ['ARTIFACTS_OUT'] = 'artifacts/%s' % name
 
   docker_args=[]
   for k,v in environ.items():
@@ -65,9 +66,20 @@
   return jobspec
 
 
-def create_jobspec(name, cmdline, environ=None, shell=False,
-                   flake_retries=0, timeout_retries=0, timeout_seconds=30*60):
+def create_jobspec(name, cmdline, environ={}, shell=False,
+                   flake_retries=0, timeout_retries=0, timeout_seconds=30*60,
+                   use_workspace=False,
+                   cpu_cost=1.0):
   """Creates jobspec."""
+  environ = environ.copy()
+  if use_workspace:
+    environ['WORKSPACE_NAME'] = 'workspace_%s' % name
+    environ['ARTIFACTS_OUT'] = os.path.join('..', 'artifacts', name)
+    cmdline = ['bash',
+               'tools/run_tests/artifacts/run_in_workspace.sh'] + cmdline
+  else:
+    environ['ARTIFACTS_OUT'] = os.path.join('artifacts', name)
+
   jobspec = jobset.JobSpec(
           cmdline=cmdline,
           environ=environ,
@@ -75,7 +87,8 @@
           timeout_seconds=timeout_seconds,
           flake_retries=flake_retries,
           timeout_retries=timeout_retries,
-          shell=shell)
+          shell=shell,
+          cpu_cost=cpu_cost)
   return jobspec
 
 
@@ -137,13 +150,14 @@
                              dir
                             ],
                             environ=environ,
-                            shell=True)
+                            use_workspace=True)
     else:
       environ['PYTHON'] = self.py_version
       environ['SKIP_PIP_INSTALL'] = 'TRUE'
       return create_jobspec(self.name,
                             ['tools/run_tests/artifacts/build_artifact_python.sh'],
-                            environ=environ)
+                            environ=environ,
+                            use_workspace=True)
 
   def __str__(self):
     return self.name
@@ -162,20 +176,11 @@
     return []
 
   def build_jobspec(self):
-    if self.platform == 'windows':
-      raise Exception("Not supported yet")
-    else:
-      if self.platform == 'linux':
-        environ = {}
-        if self.arch == 'x86':
-          environ['SETARCH_CMD'] = 'linux32'
-        return create_docker_jobspec(self.name,
-            'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
-            'tools/run_tests/artifacts/build_artifact_ruby.sh',
-            environ=environ)
-      else:
-        return create_jobspec(self.name,
-                              ['tools/run_tests/artifacts/build_artifact_ruby.sh'])
+    # Ruby build uses docker internally and docker cannot be nested.
+    # We are using a custom workspace instead.
+    return create_jobspec(self.name,
+                          ['tools/run_tests/artifacts/build_artifact_ruby.sh'],
+                          use_workspace=True)
 
 
 class CSharpExtArtifact:
@@ -196,7 +201,7 @@
       return create_jobspec(self.name,
                             ['tools\\run_tests\\artifacts\\build_artifact_csharp.bat',
                              cmake_arch_option],
-                            shell=True)
+                            use_workspace=True)
     else:
       environ = {'CONFIG': 'opt',
                  'EMBED_OPENSSL': 'true',
@@ -216,7 +221,8 @@
         environ['LDFLAGS'] += ' %s' % archflag
         return create_jobspec(self.name,
                               ['tools/run_tests/artifacts/build_artifact_csharp.sh'],
-                              environ=environ)
+                              environ=environ,
+                              use_workspace=True)
 
   def __str__(self):
     return self.name
@@ -242,10 +248,15 @@
 
   def build_jobspec(self):
     if self.platform == 'windows':
+      # Simultaneous builds of node on the same windows machine are flaky.
+      # Set x86 build as exclusive to make sure there is only one node build
+      # at a time. See https://github.com/grpc/grpc/issues/8293
+      cpu_cost = 1e6 if self.arch != 'x64' else 1.0
       return create_jobspec(self.name,
                             ['tools\\run_tests\\artifacts\\build_artifact_node.bat',
                              self.gyp_arch],
-                            shell=True)
+                            use_workspace=True,
+                            cpu_cost=cpu_cost)
     else:
       if self.platform == 'linux':
         return create_docker_jobspec(
@@ -255,7 +266,8 @@
       else:
         return create_jobspec(self.name,
                               ['tools/run_tests/artifacts/build_artifact_node.sh',
-                               self.gyp_arch])
+                               self.gyp_arch],
+                               use_workspace=True)
 
 class PHPArtifact:
   """Builds PHP PECL package"""
@@ -277,7 +289,8 @@
           'tools/run_tests/artifacts/build_artifact_php.sh')
     else:
       return create_jobspec(self.name,
-                            ['tools/run_tests/artifacts/build_artifact_php.sh'])
+                            ['tools/run_tests/artifacts/build_artifact_php.sh'],
+                            use_workspace=True)
 
 class ProtocArtifact:
   """Builds protoc and protoc-plugin artifacts"""
@@ -310,14 +323,16 @@
         environ['CXXFLAGS'] += ' -std=c++11 -stdlib=libc++ %s' % _MACOS_COMPAT_FLAG
         return create_jobspec(self.name,
             ['tools/run_tests/artifacts/build_artifact_protoc.sh'],
-            environ=environ)
+            environ=environ,
+            use_workspace=True)
     else:
       generator = 'Visual Studio 12 Win64' if self.arch == 'x64' else 'Visual Studio 12' 
       vcplatform = 'x64' if self.arch == 'x64' else 'Win32'
       return create_jobspec(self.name,
                             ['tools\\run_tests\\artifacts\\build_artifact_protoc.bat'],
                             environ={'generator': generator,
-                                     'Platform': vcplatform})
+                                     'Platform': vcplatform},
+                            use_workspace=True)
 
   def __str__(self):
     return self.name
@@ -351,7 +366,6 @@
            PythonArtifact('windows', 'x64', 'Python34'),
            PythonArtifact('windows', 'x64', 'Python35'),
            PythonArtifact('windows', 'x64', 'Python36'),
-           RubyArtifact('linux', 'x86'),
            RubyArtifact('linux', 'x64'),
            RubyArtifact('macos', 'x64'),
            PHPArtifact('linux', 'x64'),
diff --git a/tools/run_tests/artifacts/build_artifact_csharp.bat b/tools/run_tests/artifacts/build_artifact_csharp.bat
index f84ebc5..ebb11bf 100644
--- a/tools/run_tests/artifacts/build_artifact_csharp.bat
+++ b/tools/run_tests/artifacts/build_artifact_csharp.bat
@@ -37,8 +37,8 @@
 cmake --build . --target grpc_csharp_ext --config Release
 cd ..\..\..
 
-mkdir artifacts
-copy /Y cmake\build\Win32\Release\grpc_csharp_ext.dll artifacts || copy /Y cmake\build\x64\Release\grpc_csharp_ext.dll artifacts || goto :error
+mkdir -p %ARTIFACTS_OUT%
+copy /Y cmake\build\Win32\Release\grpc_csharp_ext.dll %ARTIFACTS_OUT% || copy /Y cmake\build\x64\Release\grpc_csharp_ext.dll %ARTIFACTS_OUT% || goto :error
 
 goto :EOF
 
diff --git a/tools/run_tests/artifacts/build_artifact_csharp.sh b/tools/run_tests/artifacts/build_artifact_csharp.sh
index aed04b2..2bfa749 100755
--- a/tools/run_tests/artifacts/build_artifact_csharp.sh
+++ b/tools/run_tests/artifacts/build_artifact_csharp.sh
@@ -34,5 +34,5 @@
 
 make grpc_csharp_ext
 
-mkdir -p artifacts
-cp libs/opt/libgrpc_csharp_ext.so artifacts || cp libs/opt/libgrpc_csharp_ext.dylib artifacts
+mkdir -p "${ARTIFACTS_OUT}"
+cp libs/opt/libgrpc_csharp_ext.so "${ARTIFACTS_OUT}" || cp libs/opt/libgrpc_csharp_ext.dylib "${ARTIFACTS_OUT}"
diff --git a/tools/run_tests/artifacts/build_artifact_node.bat b/tools/run_tests/artifacts/build_artifact_node.bat
index bfd4461..da4d479 100644
--- a/tools/run_tests/artifacts/build_artifact_node.bat
+++ b/tools/run_tests/artifacts/build_artifact_node.bat
@@ -37,7 +37,7 @@
 
 call npm update || goto :error
 
-mkdir artifacts
+mkdir -p %ARTIFACTS_OUT%
 
 for %%v in (%node_versions%) do (
   call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%1
@@ -47,13 +47,13 @@
   rmdir "%HOMEDRIVE%%HOMEPATH%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q
   call .\node_modules\.bin\node-pre-gyp.cmd build package testpackage --target=%%v --target_arch=%1 || goto :error
 
-  xcopy /Y /I /S build\stage\* artifacts\ || goto :error
+  xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error
 )
 
 for %%v in (%electron_versions%) do (
   cmd /V /C "set "HOME=%HOMEDRIVE%%HOMEPATH%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package testpackage --runtime=electron --target=%%v --target_arch=%1 --disturl=https://atom.io/download/electron" || goto :error
 
-  xcopy /Y /I /S build\stage\* artifacts\ || goto :error
+  xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error
 )
 if %errorlevel% neq 0 exit /b %errorlevel%
 
diff --git a/tools/run_tests/artifacts/build_artifact_node.sh b/tools/run_tests/artifacts/build_artifact_node.sh
index 7a74755..3947bde 100755
--- a/tools/run_tests/artifacts/build_artifact_node.sh
+++ b/tools/run_tests/artifacts/build_artifact_node.sh
@@ -38,7 +38,7 @@
 
 rm -rf build || true
 
-mkdir -p artifacts
+mkdir -p "${ARTIFACTS_OUT}"
 
 npm update
 
@@ -49,11 +49,11 @@
 for version in ${node_versions[@]}
 do
   ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=$NODE_TARGET_ARCH --grpc_alpine=true
-  cp -r build/stage/* artifacts/
+  cp -r build/stage/* "${ARTIFACTS_OUT}"/
 done
 
 for version in ${electron_versions[@]}
 do
   HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --runtime=electron --target=$version --target_arch=$NODE_TARGET_ARCH --disturl=https://atom.io/download/electron
-  cp -r build/stage/* artifacts/
+  cp -r build/stage/* "${ARTIFACTS_OUT}"/
 done
diff --git a/tools/run_tests/artifacts/build_artifact_php.sh b/tools/run_tests/artifacts/build_artifact_php.sh
index c8d5586..d7f8c8f 100755
--- a/tools/run_tests/artifacts/build_artifact_php.sh
+++ b/tools/run_tests/artifacts/build_artifact_php.sh
@@ -33,8 +33,8 @@
 
 cd $(dirname $0)/../../..
 
-mkdir -p artifacts
+mkdir -p "${ARTIFACTS_OUT}"
 
 pear package
 
-cp -r grpc-*.tgz artifacts/
+cp -r grpc-*.tgz "${ARTIFACTS_OUT}"/
diff --git a/tools/run_tests/artifacts/build_artifact_protoc.bat b/tools/run_tests/artifacts/build_artifact_protoc.bat
index b2bf86d..def64bd 100644
--- a/tools/run_tests/artifacts/build_artifact_protoc.bat
+++ b/tools/run_tests/artifacts/build_artifact_protoc.bat
@@ -27,7 +27,7 @@
 @rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-mkdir artifacts
+mkdir -p %ARTIFACTS_OUT%
 
 setlocal
 cd third_party/protobuf/cmake
@@ -39,8 +39,8 @@
 
 call vsprojects/build_plugins.bat || goto :error
 
-xcopy /Y third_party\protobuf\cmake\build\solution\Release\protoc.exe artifacts\ || goto :error
-xcopy /Y vsprojects\Release\*_plugin.exe artifacts\ || xcopy /Y vsprojects\x64\Release\*_plugin.exe artifacts\ || goto :error
+xcopy /Y third_party\protobuf\cmake\build\solution\Release\protoc.exe %ARTIFACTS_OUT%\ || goto :error
+xcopy /Y vsprojects\Release\*_plugin.exe %ARTIFACTS_OUT%\ || xcopy /Y vsprojects\x64\Release\*_plugin.exe %ARTIFACTS_OUT%\ || goto :error
 
 goto :EOF
 
diff --git a/tools/run_tests/artifacts/build_artifact_protoc.sh b/tools/run_tests/artifacts/build_artifact_protoc.sh
index 26c2280..df78203 100755
--- a/tools/run_tests/artifacts/build_artifact_protoc.sh
+++ b/tools/run_tests/artifacts/build_artifact_protoc.sh
@@ -37,5 +37,5 @@
 
 make plugins
 
-mkdir -p artifacts
-cp bins/opt/protobuf/protoc bins/opt/*_plugin artifacts/
+mkdir -p "${ARTIFACTS_OUT}"
+cp bins/opt/protobuf/protoc bins/opt/*_plugin "${ARTIFACTS_OUT}"/
diff --git a/tools/run_tests/artifacts/build_artifact_python.bat b/tools/run_tests/artifacts/build_artifact_python.bat
index 246713a..860b9e8 100644
--- a/tools/run_tests/artifacts/build_artifact_python.bat
+++ b/tools/run_tests/artifacts/build_artifact_python.bat
@@ -38,8 +38,9 @@
 
 @rem Multiple builds are running simultaneously, so to avoid distutils
 @rem file collisions, we build everything in a tmp directory
-if not exist "artifacts" mkdir "artifacts"
-set ARTIFACT_DIR=%cd%\artifacts
+@rem TODO(jtattermusch): it doesn't look like builds are actually running in parallel in the same dir
+mkdir -p %ARTIFACTS_OUT%
+set ARTIFACT_DIR=%cd%\%ARTIFACTS_OUT%
 set BUILD_DIR=C:\Windows\Temp\pygrpc-%3\
 mkdir %BUILD_DIR%
 xcopy /s/e/q %cd%\* %BUILD_DIR%
diff --git a/tools/run_tests/artifacts/build_artifact_python.sh b/tools/run_tests/artifacts/build_artifact_python.sh
index 5a55060..a1f0a58 100755
--- a/tools/run_tests/artifacts/build_artifact_python.sh
+++ b/tools/run_tests/artifacts/build_artifact_python.sh
@@ -41,8 +41,9 @@
 # Because multiple builds run in parallel, some distutils file
 # operations may collide.  To avoid this, each build is run in
 # a temp directory
-mkdir -p artifacts
-ARTIFACT_DIR="$PWD/artifacts"
+# TODO(jtattermusch): it doesn't look like builds are actually running in parallel in the same dir
+mkdir -p "${ARTIFACTS_OUT}"
+ARTIFACT_DIR="$PWD/${ARTIFACTS_OUT}"
 BUILD_DIR=`mktemp -d "${TMPDIR:-/tmp}/pygrpc.XXXXXX"`
 trap "rm -rf $BUILD_DIR" EXIT
 cp -r * "$BUILD_DIR"
diff --git a/tools/run_tests/artifacts/build_artifact_ruby.sh b/tools/run_tests/artifacts/build_artifact_ruby.sh
index ca461ba..c92d7a8 100755
--- a/tools/run_tests/artifacts/build_artifact_ruby.sh
+++ b/tools/run_tests/artifacts/build_artifact_ruby.sh
@@ -63,6 +63,6 @@
   rm `ls pkg/*.gem | grep -v darwin`
 fi
 
-mkdir -p artifacts
+mkdir -p "${ARTIFACTS_OUT}"
 
-cp pkg/*.gem artifacts
+cp pkg/*.gem "${ARTIFACTS_OUT}"/
diff --git a/tools/run_tests/artifacts/build_package_node.sh b/tools/run_tests/artifacts/build_package_node.sh
index 8b5e8c0..d06f141 100755
--- a/tools/run_tests/artifacts/build_package_node.sh
+++ b/tools/run_tests/artifacts/build_package_node.sh
@@ -40,7 +40,7 @@
 artifacts=$base/artifacts
 
 mkdir -p $artifacts
-cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=node,platform={windows,linux,macos}/artifacts/* $artifacts/ || true
+cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/node_ext_*/* $artifacts/ || true
 
 npm update
 npm pack
@@ -86,7 +86,7 @@
         ;;
     esac
     rm -r bin/*
-    input_dir="$EXTERNAL_GIT_ROOT/architecture=$arch,language=protoc,platform=$plat/artifacts"
+    input_dir="$EXTERNAL_GIT_ROOT/platform=${plat}/artifacts/protoc_${plat}_${arch}"
     cp $input_dir/protoc* bin/
     cp $input_dir/grpc_node_plugin* bin/
     mkdir -p bin/google/protobuf
diff --git a/tools/run_tests/artifacts/build_package_php.sh b/tools/run_tests/artifacts/build_package_php.sh
index 42a8d9f..16da58d 100755
--- a/tools/run_tests/artifacts/build_package_php.sh
+++ b/tools/run_tests/artifacts/build_package_php.sh
@@ -33,4 +33,4 @@
 cd $(dirname $0)/../../..
 
 mkdir -p artifacts/
-cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=php,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/php_*/* artifacts/ || true
diff --git a/tools/run_tests/artifacts/build_package_python.sh b/tools/run_tests/artifacts/build_package_python.sh
index 4a1c15c..9148bb0 100755
--- a/tools/run_tests/artifacts/build_package_python.sh
+++ b/tools/run_tests/artifacts/build_package_python.sh
@@ -36,7 +36,7 @@
 
 # All the python packages have been built in the artifact phase already
 # and we only collect them here to deliver them to the distribtest phase.
-cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=python,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/python_*/* artifacts/ || true
 
 # TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
 # source distribution package, and only one of them will end up
diff --git a/tools/run_tests/artifacts/build_package_ruby.sh b/tools/run_tests/artifacts/build_package_ruby.sh
index b4d20d8..8388b84 100755
--- a/tools/run_tests/artifacts/build_package_ruby.sh
+++ b/tools/run_tests/artifacts/build_package_ruby.sh
@@ -38,7 +38,7 @@
 
 # All the ruby packages have been built in the artifact phase already
 # and we only collect them here to deliver them to the distribtest phase.
-cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=ruby,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/ruby_native_gem_*/* artifacts/ || true
 
 well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers )
 
@@ -56,7 +56,7 @@
       ;;
   esac
   for plat in {windows,linux,macos}; do
-    input_dir="$EXTERNAL_GIT_ROOT/architecture=$arch,language=protoc,platform=$plat/artifacts"
+    input_dir="$EXTERNAL_GIT_ROOT/platform=${plat}/artifacts/protoc_${plat}_${arch}"
     output_dir="$base/src/ruby/tools/bin/${ruby_arch}-${plat}"
     mkdir -p $output_dir/google/protobuf
     mkdir -p $output_dir/google/protobuf/compiler  # needed for plugin.proto
diff --git a/tools/run_tests/artifacts/distribtest_targets.py b/tools/run_tests/artifacts/distribtest_targets.py
index 097fd2d..3cb7d97 100644
--- a/tools/run_tests/artifacts/distribtest_targets.py
+++ b/tools/run_tests/artifacts/distribtest_targets.py
@@ -63,8 +63,14 @@
 
 
 def create_jobspec(name, cmdline, environ=None, shell=False,
-                   flake_retries=0, timeout_retries=0):
+                   flake_retries=0, timeout_retries=0,
+                   use_workspace=False):
   """Creates jobspec."""
+  environ = environ.copy()
+  if use_workspace:
+    environ['WORKSPACE_NAME'] = 'workspace_%s' % name
+    cmdline = ['bash',
+               'tools/run_tests/artifacts/run_in_workspace.sh'] + cmdline
   jobspec = jobset.JobSpec(
           cmdline=cmdline,
           environ=environ,
@@ -80,7 +86,7 @@
   """Tests C# NuGet package"""
 
   def __init__(self, platform, arch, docker_suffix=None, use_dotnet_cli=False):
-    self.name = 'csharp_nuget_%s_%s' % (platform, arch)
+    self.name = 'csharp_%s_%s' % (platform, arch)
     self.platform = platform
     self.arch = arch
     self.docker_suffix = docker_suffix
@@ -110,16 +116,18 @@
     elif self.platform == 'macos':
       return create_jobspec(self.name,
           ['test/distrib/csharp/run_distrib_test%s.sh' % self.script_suffix],
-          environ={'EXTERNAL_GIT_ROOT': '../../..'})
+          environ={'EXTERNAL_GIT_ROOT': '../../../..'},
+          use_workspace=True)
     elif self.platform == 'windows':
       if self.arch == 'x64':
         environ={'MSBUILD_EXTRA_ARGS': '/p:Platform=x64',
                  'DISTRIBTEST_OUTPATH': 'DistribTest\\bin\\x64\\Debug'}
       else:
-        environ={'DISTRIBTEST_OUTPATH': 'DistribTest\\bin\\\Debug'}
+        environ={'DISTRIBTEST_OUTPATH': 'DistribTest\\bin\\Debug'}
       return create_jobspec(self.name,
           ['test\\distrib\\csharp\\run_distrib_test%s.bat' % self.script_suffix],
-          environ=environ)
+          environ=environ,
+          use_workspace=True)
     else:
       raise Exception("Not supported yet.")
 
@@ -161,7 +169,8 @@
       return create_jobspec(self.name,
                             ['test/distrib/node/run_distrib_test.sh',
                              str(self.node_version)],
-                            environ={'EXTERNAL_GIT_ROOT': '../../..'})
+                            environ={'EXTERNAL_GIT_ROOT': '../../../..'},
+                            use_workspace=True)
     else:
       raise Exception("Not supported yet.")
 
@@ -249,7 +258,8 @@
     elif self.platform == 'macos':
       return create_jobspec(self.name,
           ['test/distrib/php/run_distrib_test.sh'],
-          environ={'EXTERNAL_GIT_ROOT': '../../..'})
+          environ={'EXTERNAL_GIT_ROOT': '../../../..'},
+          use_workspace=True)
     else:
       raise Exception("Not supported yet.")
 
@@ -339,5 +349,5 @@
             NodeDistribTest('linux', 'x64', os, version)
             for os in ('wheezy', 'jessie', 'ubuntu1204', 'ubuntu1404',
                        'ubuntu1504', 'ubuntu1510', 'ubuntu1604')
-            for version in ('0.12', '3', '4', '5')
+            for version in ('4', '5')
           ]
diff --git a/tools/grpcz/BUILD b/tools/run_tests/artifacts/run_in_workspace.sh
old mode 100644
new mode 100755
similarity index 66%
copy from tools/grpcz/BUILD
copy to tools/run_tests/artifacts/run_in_workspace.sh
index cc887a5..ed3bfda
--- a/tools/grpcz/BUILD
+++ b/tools/run_tests/artifacts/run_in_workspace.sh
@@ -1,4 +1,5 @@
-# Copyright 2017, Google Inc.
+#!/bin/bash
+# Copyright 2015, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -26,38 +27,21 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Create a workspace in a subdirectory to allow running multiple builds in isolation.
+# WORKSPACE_NAME env variable needs to contain name of the workspace to create.
+# All cmdline args will be executed as a command.
+set -ex
 
-licenses(["notice"])  # 3-clause BSD
+cd $(dirname $0)/../../..
+export repo_root=$(pwd)
 
-package(default_visibility = ["//visibility:public"])
+rm -rf "${WORKSPACE_NAME}"
+git clone . "${WORKSPACE_NAME}"
+# clone gRPC submodules, use data from locally cloned submodules where possible
+git submodule foreach 'cd "${repo_root}/${WORKSPACE_NAME}" \
+    && git submodule update --init --reference ${repo_root}/${name} ${name}'
 
-load("//:bazel/grpc_build_system.bzl", "grpc_proto_library")
-
-grpc_proto_library(
-    name = "monitoring_proto",
-    srcs = [
-        "monitoring.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-    deps = [
-        ":census_proto",
-    ],
-)
-
-grpc_proto_library(
-    name = "census_proto",
-    srcs = [
-        "census.proto",
-    ],
-    well_known_protos = "@com_google_protobuf//:well_known_protos",
-)
-
-cc_binary(
-    name = "grpcz_client",
-    srcs = ["grpcz_client.cc"],
-    deps = [
-        "monitoring_proto",
-        "//external:gflags",
-        "@mongoose_repo//:mongoose_lib",
-    ],
-)
+echo "Running in workspace ${WORKSPACE_NAME}"
+cd ${WORKSPACE_NAME}
+$@
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index a488c15..a5d7fda 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -5064,6 +5064,24 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "src": [
+      "test/core/end2end/fixtures/h2_full+workarounds.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "end2end_tests", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "h2_http_proxy_test", 
     "src": [
       "test/core/end2end/fixtures/h2_http_proxy.c"
@@ -5370,6 +5388,24 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "src": [
+      "test/core/end2end/fixtures/h2_full+workarounds.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "end2end_nosec_tests", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "h2_http_proxy_nosec_test", 
     "src": [
       "test/core/end2end/fixtures/h2_http_proxy.c"
@@ -5764,10 +5800,12 @@
       "grpc_resolver_dns_native", 
       "grpc_resolver_sockaddr", 
       "grpc_secure", 
+      "grpc_server_backward_compatibility", 
       "grpc_transport_chttp2_client_insecure", 
       "grpc_transport_chttp2_client_secure", 
       "grpc_transport_chttp2_server_insecure", 
-      "grpc_transport_chttp2_server_secure"
+      "grpc_transport_chttp2_server_secure", 
+      "grpc_workaround_cronet_compression_filter"
     ], 
     "headers": [], 
     "is_filegroup": false, 
@@ -5868,8 +5906,10 @@
       "grpc_resolver_dns_ares", 
       "grpc_resolver_dns_native", 
       "grpc_resolver_sockaddr", 
+      "grpc_server_backward_compatibility", 
       "grpc_transport_chttp2_client_insecure", 
-      "grpc_transport_chttp2_server_insecure"
+      "grpc_transport_chttp2_server_insecure", 
+      "grpc_workaround_cronet_compression_filter"
     ], 
     "headers": [], 
     "is_filegroup": false, 
@@ -7402,6 +7442,7 @@
       "test/core/end2end/tests/simple_request.c", 
       "test/core/end2end/tests/streaming_error_response.c", 
       "test/core/end2end/tests/trailing_metadata.c", 
+      "test/core/end2end/tests/workaround_cronet_compression.c", 
       "test/core/end2end/tests/write_buffering.c", 
       "test/core/end2end/tests/write_buffering_at_end.c"
     ], 
@@ -7477,6 +7518,7 @@
       "test/core/end2end/tests/simple_request.c", 
       "test/core/end2end/tests/streaming_error_response.c", 
       "test/core/end2end/tests/trailing_metadata.c", 
+      "test/core/end2end/tests/workaround_cronet_compression.c", 
       "test/core/end2end/tests/write_buffering.c", 
       "test/core/end2end/tests/write_buffering_at_end.c"
     ], 
@@ -7746,6 +7788,7 @@
       "include/grpc/slice.h", 
       "include/grpc/slice_buffer.h", 
       "include/grpc/status.h", 
+      "include/grpc/support/workaround_list.h", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
       "src/core/lib/channel/channel_stack_builder.h", 
@@ -7873,6 +7916,7 @@
       "include/grpc/slice.h", 
       "include/grpc/slice_buffer.h", 
       "include/grpc/status.h", 
+      "include/grpc/support/workaround_list.h", 
       "src/core/lib/channel/channel_args.c", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.c", 
@@ -7925,6 +7969,7 @@
       "src/core/lib/iomgr/ev_poll_posix.h", 
       "src/core/lib/iomgr/ev_posix.c", 
       "src/core/lib/iomgr/ev_posix.h", 
+      "src/core/lib/iomgr/ev_windows.c", 
       "src/core/lib/iomgr/exec_ctx.c", 
       "src/core/lib/iomgr/exec_ctx.h", 
       "src/core/lib/iomgr/executor.c", 
@@ -8557,6 +8602,24 @@
   }, 
   {
     "deps": [
+      "gpr", 
+      "grpc_base"
+    ], 
+    "headers": [
+      "src/core/ext/filters/workarounds/workaround_utils.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_server_backward_compatibility", 
+    "src": [
+      "src/core/ext/filters/workarounds/workaround_utils.c", 
+      "src/core/ext/filters/workarounds/workaround_utils.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
       "gpr_test_util", 
       "grpc"
     ], 
@@ -8867,6 +8930,25 @@
     "type": "filegroup"
   }, 
   {
+    "deps": [
+      "gpr", 
+      "grpc_base", 
+      "grpc_server_backward_compatibility"
+    ], 
+    "headers": [
+      "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_workaround_cronet_compression_filter", 
+    "src": [
+      "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c", 
+      "src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
     "deps": [], 
     "headers": [
       "third_party/nanopb/pb.h", 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 48f24ab..d1e3a99 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -2805,7 +2805,7 @@
   }, 
   {
     "args": [
-      "--benchmark_min_time=0"
+      "--benchmark_min_time=4"
     ], 
     "ci_platforms": [
       "linux", 
@@ -7077,6 +7077,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -8277,6 +8300,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -9449,6 +9495,28 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -10505,6 +10573,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -11728,6 +11819,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -12743,6 +12857,25 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -13912,6 +14045,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -13963,6 +14119,1252 @@
     "ci_platforms": [
       "windows", 
       "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "bad_hostname"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "binary_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "call_creds"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_accept"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_client_done"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_before_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_in_a_vacuum"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_with_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "compressed_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "connectivity"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "default_host"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "disappearing_server"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": true, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "empty_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_causes_close"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_latency"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "graceful_server_shutdown"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "high_initial_seqno"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "hpack_size"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "idempotent_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "invoke_large_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "keepalive_timeout"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "large_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_concurrent_streams"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_connection_age"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_connection_idle"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_message_length"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "negative_deadline"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "network_status_change"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "no_op"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping_pong_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "registered_call"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_flags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "resource_quota_server"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "server_finishes_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_calls"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_tags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_cacheable_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_delayed_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "trailing_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "write_buffering"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "write_buffering_at_end"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "authority_not_supported"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -15182,6 +16584,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -16407,6 +17833,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -17677,6 +19126,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -18709,6 +20182,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -19813,6 +21310,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -20845,6 +22366,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -22011,6 +23556,32 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [
+      "msan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -23240,6 +24811,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -24463,6 +26057,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_cert_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -25493,6 +27110,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -26691,6 +28332,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -27891,6 +29555,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -29068,6 +30755,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -30103,6 +31813,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -31303,6 +33036,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -32299,6 +34055,25 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -33445,6 +35220,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -33496,6 +35294,1229 @@
     "ci_platforms": [
       "windows", 
       "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "bad_hostname"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "bad_ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "binary_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_accept"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_client_done"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_before_invoke"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_in_a_vacuum"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_with_status"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "compressed_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "connectivity"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "default_host"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "disappearing_server"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": true, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "empty_batch"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_call_init_fails"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_causes_close"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "filter_latency"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "graceful_server_shutdown"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "high_initial_seqno"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "hpack_size"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "idempotent_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "invoke_large_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "keepalive_timeout"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "large_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "load_reporting_hook"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_concurrent_streams"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_connection_age"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_connection_idle"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "max_message_length"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "negative_deadline"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "network_status_change"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "no_op"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "ping_pong_streaming"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "registered_call"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_flags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "request_with_payload"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "resource_quota_server"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "server_finishes_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_calls"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "shutdown_finishes_tags"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_cacheable_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_delayed_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "simple_request"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "streaming_error_response"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "trailing_metadata"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "write_buffering"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "write_buffering_at_end"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "authority_not_supported"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
       "posix"
     ], 
     "cpu_cost": 1.0, 
@@ -34691,6 +37712,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -35893,6 +38938,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -36899,6 +39967,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -37979,6 +41071,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -38987,6 +42103,30 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -40127,6 +43267,32 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [
+      "msan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -41306,6 +44472,29 @@
   }, 
   {
     "args": [
+      "workaround_cronet_compression"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "write_buffering"
     ], 
     "ci_platforms": [
@@ -41353,6 +44542,56 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_1channel_100rpcs_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_1channel_100rpcs_1MB", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_1channel_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "tsan", 
+      "asan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_1channel_1MB", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
@@ -42911,6 +46150,82 @@
   {
     "args": [
       "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_unary_1channel_100rpcs_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_unary_1channel_100rpcs_1MB_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
+      "{\"scenarios\": [{\"name\": \"cpp_protobuf_async_streaming_from_client_1channel_1MB\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 0, \"security_params\": null, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": null, \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING_FROM_CLIENT\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
+    ], 
+    "boringssl": true, 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": "capacity", 
+    "defaults": "boringssl", 
+    "exclude_configs": [
+      "asan-noleaks", 
+      "asan-trace-cmp", 
+      "basicprof", 
+      "c++-compat", 
+      "counters", 
+      "dbg", 
+      "gcov", 
+      "helgrind", 
+      "lto", 
+      "memcheck", 
+      "msan", 
+      "mutrace", 
+      "opt", 
+      "stapprof", 
+      "ubsan"
+    ], 
+    "excluded_poll_engines": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "json_run_localhost", 
+    "platforms": [
+      "linux"
+    ], 
+    "shortname": "json_run_localhost:cpp_protobuf_async_streaming_from_client_1channel_1MB_low_thread_count", 
+    "timeout_seconds": 360
+  }, 
+  {
+    "args": [
+      "--scenarios_json", 
       "{\"scenarios\": [{\"name\": \"cpp_generic_async_streaming_ping_pong_secure\", \"warmup_seconds\": 0, \"benchmark_seconds\": 1, \"num_servers\": 1, \"server_config\": {\"async_server_threads\": 1, \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"server_type\": \"ASYNC_GENERIC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"client_type\": \"ASYNC_CLIENT\", \"security_params\": {\"use_test_ca\": true, \"server_host_override\": \"foo.test.google.fr\"}, \"payload_config\": {\"bytebuf_params\": {\"resp_size\": 0, \"req_size\": 0}}, \"client_channels\": 1, \"async_client_threads\": 1, \"outstanding_rpcs_per_channel\": 1, \"rpc_type\": \"STREAMING\", \"load_params\": {\"closed_loop\": {}}, \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
     "boringssl": true, 
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
index 28397be..6ad285c 100755
--- a/tools/run_tests/helper_scripts/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -187,7 +187,8 @@
 pip_install_dir $ROOT/src/python/grpcio_reflection
 
 # Build/install tests
-$VENV_PYTHON -m pip install coverage oauth2client
+$VENV_PYTHON -m pip install coverage==4.4 oauth2client==4.1.0 \
+                            google-auth==1.0.0 requests==2.14.2
 $VENV_PYTHON $ROOT/src/python/grpcio_tests/setup.py preprocess
 $VENV_PYTHON $ROOT/src/python/grpcio_tests/setup.py build_package_protos
 pip_install_dir $ROOT/src/python/grpcio_tests
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 8ed675e..c2ffd67 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -112,6 +112,7 @@
                         categories=DEFAULT_CATEGORIES,
                         channels=None,
                         outstanding=None,
+                        num_clients=None,
                         resource_quota_size=None,
                         messages_per_stream=None,
                         excluded_poll_engines=[]):
@@ -158,7 +159,7 @@
     wide = channels if channels is not None else WIDE
     deep = int(math.ceil(1.0 * outstanding_calls / wide))
 
-    scenario['num_clients'] = 0  # use as many client as available.
+    scenario['num_clients'] = num_clients if num_clients is not None else 0  # use as many clients as available.
     scenario['client_config']['outstanding_rpcs_per_channel'] = deep
     scenario['client_config']['client_channels'] = wide
     scenario['client_config']['async_client_threads'] = 0
@@ -196,6 +197,24 @@
 
   def scenarios(self):
     # TODO(ctiller): add 70% load latency test
+    yield _ping_pong_scenario(
+      'cpp_protobuf_async_unary_1channel_100rpcs_1MB', rpc_type='UNARY',
+      client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+      req_size=1024*1024, resp_size=1024*1024,
+      unconstrained_client='async', outstanding=100, channels=1,
+      num_clients=1,
+      secure=False,
+      categories=[SMOKETEST] + [SCALABLE])
+
+    yield _ping_pong_scenario(
+      'cpp_protobuf_async_streaming_from_client_1channel_1MB', rpc_type='STREAMING_FROM_CLIENT',
+      client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER',
+      req_size=1024*1024, resp_size=1024*1024,
+      unconstrained_client='async', outstanding=1, channels=1,
+      num_clients=1,
+      secure=False,
+      categories=[SMOKETEST] + [SCALABLE])
+
     for secure in [True, False]:
       secstr = 'secure' if secure else 'insecure'
       smoketest_categories = ([SMOKETEST] if secure else []) + [SCALABLE]
diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py
index 4e97128..3754035 100755
--- a/tools/run_tests/python_utils/jobset.py
+++ b/tools/run_tests/python_utils/jobset.py
@@ -225,6 +225,22 @@
     self.cpu_estimated = 1
     self.cpu_measured = 0
 
+
+def eintr_be_gone(fn):
+  """Run fn until it doesn't stop because of EINTR"""
+  while True:
+    try:
+      return fn()
+    except IOError, e:
+      if e.errno != errno.EINTR:
+        raise
+
+
+def read_from_start(f):
+  f.seek(0)
+  return f.read()
+
+
 class Job(object):
   """Manages one job."""
 
@@ -255,7 +271,7 @@
     self._start = time.time()
     cmdline = self._spec.cmdline
     if measure_cpu_costs:
-      cmdline = ['time', '--portability'] + cmdline
+      cmdline = ['time', '-p'] + cmdline
     try_start = lambda: subprocess.Popen(args=cmdline,
                                          stderr=subprocess.STDOUT,
                                          stdout=self._tempfile,
@@ -278,8 +294,7 @@
   def state(self):
     """Poll current state of the job. Prints messages at completion."""
     def stdout(self=self):
-      self._tempfile.seek(0)
-      stdout = self._tempfile.read()
+      stdout = read_from_start(self._tempfile)
       self.result.message = stdout[-_MAX_RESULT_SIZE:]
       return stdout
     if self._state == _RUNNING and self._process.poll() is not None:
@@ -307,7 +322,7 @@
         self._state = _SUCCESS
         measurement = ''
         if measure_cpu_costs:
-          m = re.search(r'real ([0-9.]+)\nuser ([0-9.]+)\nsys ([0-9.]+)', stdout())
+          m = re.search(r'real\s+([0-9.]+)\nuser\s+([0-9.]+)\nsys\s+([0-9.]+)', stdout())
           real = float(m.group(1))
           user = float(m.group(2))
           sys = float(m.group(3))
@@ -415,7 +430,7 @@
     while self._running:
       dead = set()
       for job in self._running:
-        st = job.state()
+        st = eintr_be_gone(lambda: job.state())
         if st == _RUNNING: continue
         if st == _FAILURE or st == _KILLED:
           self._failures += 1
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 867d9e6..ae2da26 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -581,7 +581,7 @@
   env = {}
 
   # TODO(jtattermusch): this file path only works inside docker
-  key_filepath = '/root/service_account/stubbyCloudTestingTest-ee3fce360ac5.json'
+  key_filepath = '/root/service_account/GrpcTesting-726eb1347f15.json'
   oauth_scope_arg = '--oauth_scope=https://www.googleapis.com/auth/xapi.zoo'
   key_file_arg = '--service_account_key_file=%s' % key_filepath
   default_account_arg = '--default_service_account=830293263384-compute@developer.gserviceaccount.com'
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 83a8394..1a16b09 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -75,8 +75,9 @@
 
 
 _POLLING_STRATEGIES = {
-  'linux': ['epollsig', 'poll', 'poll-cv']
+  'linux': ['epollsig', 'poll', 'poll-cv'],
 # TODO(ctiller, sreecha): enable epoll1, epollex, epoll-thread-pool
+  'mac': ['poll'],
 }
 
 
@@ -340,7 +341,8 @@
     if self.platform == 'windows':
       # don't build tools on windows just yet
       return ['buildtests_%s' % self.make_target]
-    return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target]
+    return ['buildtests_%s' % self.make_target, 'tools_%s' % self.make_target,
+            'check_epollexclusive']
 
   def make_options(self):
     return self._make_options;
diff --git a/tools/run_tests/task_runner.py b/tools/run_tests/task_runner.py
index 0ec7efb..7feac29 100755
--- a/tools/run_tests/task_runner.py
+++ b/tools/run_tests/task_runner.py
@@ -40,6 +40,7 @@
 import artifacts.distribtest_targets as distribtest_targets
 import artifacts.package_targets as package_targets
 import python_utils.jobset as jobset
+import python_utils.report_utils as report_utils
 
 _TARGETS = []
 _TARGETS += artifact_targets.targets()
@@ -116,8 +117,10 @@
   sys.exit(1)
 
 jobset.message('START', 'Building targets.', do_newline=True)
-num_failures, _ = jobset.run(
+num_failures, resultset = jobset.run(
     build_jobs, newline_on_success=True, maxjobs=args.jobs)
+report_utils.render_junit_xml_report(resultset, 'report_taskrunner_sponge_log.xml',
+                                     suite_name='tasks')
 if num_failures == 0:
   jobset.message('SUCCESS', 'All targets built successfully.',
                  do_newline=True)
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 2e8ccf8..97a75e7 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -824,6 +824,30 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "h2_full+workarounds_nosec_test", "vcxproj\test/end2end/fixtures\h2_full+workarounds_nosec_test\h2_full+workarounds_nosec_test.vcxproj", "{77F11A97-AECB-10F5-50E8-1482F658A2D3}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED} = {47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}
+		{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF} = {0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}
+		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}
+		{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}") = "h2_full+workarounds_test", "vcxproj\test/end2end/fixtures\h2_full+workarounds_test\h2_full+workarounds_test.vcxproj", "{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{1F1F9084-2A93-B80E-364F-5754894AFAB4} = {1F1F9084-2A93-B80E-364F-5754894AFAB4}
+		{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}") = "h2_full_nosec_test", "vcxproj\test/end2end/fixtures\h2_full_nosec_test\h2_full_nosec_test.vcxproj", "{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -2979,6 +3003,38 @@
 		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|Win32.Build.0 = Release|Win32
 		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|x64.ActiveCfg = Release|x64
 		{16C713C6-062E-F71F-A44C-52DC35494B27}.Release-DLL|x64.Build.0 = Release|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug|x64.ActiveCfg = Debug|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release|Win32.ActiveCfg = Release|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release|x64.ActiveCfg = Release|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug|Win32.Build.0 = Debug|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug|x64.Build.0 = Debug|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release|Win32.Build.0 = Release|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release|x64.Build.0 = Release|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Debug-DLL|x64.Build.0 = Debug|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release-DLL|Win32.Build.0 = Release|Win32
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release-DLL|x64.ActiveCfg = Release|x64
+		{77F11A97-AECB-10F5-50E8-1482F658A2D3}.Release-DLL|x64.Build.0 = Release|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug|Win32.ActiveCfg = Debug|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug|x64.ActiveCfg = Debug|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release|Win32.ActiveCfg = Release|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release|x64.ActiveCfg = Release|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug|Win32.Build.0 = Debug|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug|x64.Build.0 = Debug|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release|Win32.Build.0 = Release|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release|x64.Build.0 = Release|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Debug-DLL|x64.Build.0 = Debug|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release-DLL|Win32.Build.0 = Release|Win32
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release-DLL|x64.ActiveCfg = Release|x64
+		{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}.Release-DLL|x64.Build.0 = Release|x64
 		{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}.Debug|Win32.ActiveCfg = Debug|Win32
 		{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}.Debug|x64.ActiveCfg = Debug|x64
 		{345EA50E-BCD4-DAC7-E1C8-DDA6291B75E2}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/protoc.props b/vsprojects/protoc.props
index 87fff8f..6c842c2 100644
--- a/vsprojects/protoc.props
+++ b/vsprojects/protoc.props
@@ -1 +1 @@
-<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ImportGroup Label="PropertySheets" /> <PropertyGroup Label="UserMacros" /> <PropertyGroup /> <ItemDefinitionGroup> <ClCompile> <DisableSpecificWarnings>4244;4267;%(DisableSpecificWarnings)</DisableSpecificWarnings> </ClCompile> <Link> <AdditionalDependencies>libprotoc.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories>$(SolutionDir)\..\third_party\protobuf\cmake\build\solution\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup /> </Project>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ImportGroup Label="PropertySheets" /> <PropertyGroup Label="UserMacros" /> <PropertyGroup /> <ItemDefinitionGroup> <ClCompile> <DisableSpecificWarnings>4244;4267;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> </ClCompile> <Link> <AdditionalDependencies>libprotoc.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories>$(SolutionDir)\..\third_party\protobuf\cmake\build\solution\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> </Link> </ItemDefinitionGroup> <ItemGroup /> </Project>
\ No newline at end of file
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index f8fae96..ae51c43 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -361,6 +361,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
   </ItemGroup>
@@ -629,6 +630,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 7335375..12eef94 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -202,6 +202,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.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>
@@ -825,6 +828,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
@@ -1256,6 +1262,9 @@
     <Filter Include="include\grpc\impl\codegen">
       <UniqueIdentifier>{dc8bfccd-341f-26f0-8ee4-47dde62a6dd1}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\support">
+      <UniqueIdentifier>{5ec10a44-9a09-9220-cf3b-b18ce6e4f70f}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{328ff211-2886-406e-56f9-18ba1686f363}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 02e3399..bd10536 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -361,6 +361,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
@@ -613,6 +614,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 5d7f082..f1f4f17 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -187,6 +187,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.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>
@@ -810,6 +813,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
@@ -1223,6 +1229,9 @@
     <Filter Include="include\grpc\impl\codegen">
       <UniqueIdentifier>{adf6b8e3-4a4b-cb35-bb3d-568af97b58d1}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\support">
+      <UniqueIdentifier>{9d6d36f2-26e7-a66b-c19d-a958b80878d6}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{cce6a85d-1111-3834-6825-31e170d93cff}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index d32958d..2ccda23 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -277,6 +277,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.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" />
@@ -514,6 +515,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
@@ -570,6 +573,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
@@ -1004,6 +1009,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 14aa7d4..3a1c1f9 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -82,6 +82,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.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>
@@ -733,6 +736,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
       <Filter>src\core\ext\filters\message_size</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_plugin_registry.c">
       <Filter>src\core\plugin_registry</Filter>
     </ClCompile>
@@ -768,6 +777,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -1475,6 +1487,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h">
       <Filter>src\core\ext\filters\message_size</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -1490,6 +1508,9 @@
     <Filter Include="include\grpc\impl\codegen">
       <UniqueIdentifier>{def748f5-ed2a-a9bb-40d9-c31d00f0e13b}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\support">
+      <UniqueIdentifier>{31de82ea-dc6c-73fb-a640-979b8a7b240c}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{d538af37-07b2-062b-fa2a-d9f882cb2737}</UniqueIdentifier>
     </Filter>
@@ -1574,6 +1595,9 @@
     <Filter Include="src\core\ext\filters\message_size">
       <UniqueIdentifier>{5ca3f38c-539f-3c4f-b68c-38b31ba339ba}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\filters\workarounds">
+      <UniqueIdentifier>{2ec64619-e2c4-da0f-c10e-e03f5a151300}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\ext\transport">
       <UniqueIdentifier>{e3abfd0a-064e-0f2f-c8e8-7c5a7e98142a}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 2f245d5..061fca6 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -157,6 +157,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.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" />
@@ -402,6 +403,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index d2caf22..35d0ea0 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -139,6 +139,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.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>
@@ -471,6 +474,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -935,6 +941,9 @@
     <Filter Include="include\grpc\impl\codegen">
       <UniqueIdentifier>{8e97f1e1-f4d1-a56e-0837-7901778fb3b9}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\support">
+      <UniqueIdentifier>{b783a829-3703-129f-39ee-528ac0a06e06}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{7d107d7c-1da3-9525-3ba1-3a411b552ea8}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 88fa5b1..d084d70 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -268,6 +268,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\slice_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.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" />
@@ -479,6 +480,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\tracing.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\max_age\max_age_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\init.c">
@@ -537,6 +540,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
@@ -911,6 +916,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 87d7f53..ba82685 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -85,6 +85,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_windows.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>
@@ -646,6 +649,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.c">
       <Filter>src\core\ext\filters\message_size</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.c">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.c">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\plugin_registry\grpc_unsecure_plugin_registry.c">
       <Filter>src\core\plugin_registry</Filter>
     </ClCompile>
@@ -681,6 +690,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\support\workaround_list.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
       <Filter>include\grpc\impl\codegen</Filter>
     </ClInclude>
@@ -1310,6 +1322,12 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\message_size\message_size_filter.h">
       <Filter>src\core\ext\filters\message_size</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_cronet_compression_filter.h">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\workarounds\workaround_utils.h">
+      <Filter>src\core\ext\filters\workarounds</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -1325,6 +1343,9 @@
     <Filter Include="include\grpc\impl\codegen">
       <UniqueIdentifier>{03cc6735-c734-7017-4000-a435f29d55c3}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\support">
+      <UniqueIdentifier>{a553e3dc-8973-1b23-8be4-31852fd9e429}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{aaf326a1-c884-46ea-875a-cbbd9983e539}</UniqueIdentifier>
     </Filter>
@@ -1409,6 +1430,9 @@
     <Filter Include="src\core\ext\filters\message_size">
       <UniqueIdentifier>{8cbe7444-caac-49dc-be89-d4c4d1c7966a}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\filters\workarounds">
+      <UniqueIdentifier>{8bd0612e-bd53-c9e6-7b3c-20937e4e1e9e}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\ext\transport">
       <UniqueIdentifier>{967c89fe-c97c-27e2-aac0-9ba5854cb5fa}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_nosec_test/h2_full+workarounds_nosec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_nosec_test/h2_full+workarounds_nosec_test.vcxproj
new file mode 100644
index 0000000..3382da8
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_nosec_test/h2_full+workarounds_nosec_test.vcxproj
@@ -0,0 +1,191 @@
+<?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>{77F11A97-AECB-10F5-50E8-1482F658A2D3}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>h2_full+workarounds_nosec_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>h2_full+workarounds_nosec_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_full+workarounds.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\test/end2end/tests\end2end_nosec_tests\end2end_nosec_tests.vcxproj">
+      <Project>{47C2CB41-4E9F-58B6-F606-F6FAED5D00ED}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util_unsecure\grpc_test_util_unsecure.vcxproj">
+      <Project>{0A7E7F92-FDEA-40F1-A9EC-3BA484F98BBF}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_unsecure\grpc_unsecure.vcxproj">
+      <Project>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  </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')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_nosec_test/h2_full+workarounds_nosec_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_nosec_test/h2_full+workarounds_nosec_test.vcxproj.filters
new file mode 100644
index 0000000..508fdb0
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_nosec_test/h2_full+workarounds_nosec_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?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_full+workarounds.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{76d5c3df-dc83-3d8e-20cf-97c476aee0be}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{27cb2640-416a-d2be-6df2-a0ad80292e02}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{aa0ffd71-64a8-dbe3-28f4-4887b873121c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end\fixtures">
+      <UniqueIdentifier>{e8f97aab-0a43-199b-5652-5e3f3aa068ac}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_test/h2_full+workarounds_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_test/h2_full+workarounds_test.vcxproj
new file mode 100644
index 0000000..2275317
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_test/h2_full+workarounds_test.vcxproj
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{64FEC2E4-20E0-6673-DDC5-12322D26ACEE}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>h2_full+workarounds_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_full+workarounds_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>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\fixtures\h2_full+workarounds.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>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_test/h2_full+workarounds_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_test/h2_full+workarounds_test.vcxproj.filters
new file mode 100644
index 0000000..ed6579c
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/h2_full+workarounds_test/h2_full+workarounds_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?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_full+workarounds.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{e1fc3c56-15d3-b30e-4abe-d0bf3ce5274c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{741cc9d4-6e6a-0571-83c6-f9d3b60c075e}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{764873d7-3feb-0133-cfe8-3c5fb4b9c259}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end\fixtures">
+      <UniqueIdentifier>{1bc3f78e-5318-085d-7fe9-aaa95bfef3b1}</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 e3adf79..8581f0c 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
@@ -255,6 +255,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\workaround_cronet_compression.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\write_buffering.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\write_buffering_at_end.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 cfb8d04..ae2937b 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
@@ -157,6 +157,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\workaround_cronet_compression.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\write_buffering.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 a67f509..1bd0998 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -257,6 +257,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\workaround_cronet_compression.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\write_buffering.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\write_buffering_at_end.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 97ba77a..217c60e 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
@@ -160,6 +160,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\trailing_metadata.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\workaround_cronet_compression.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\write_buffering.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>