Merge pull request #11837 from dgquintas/thread_manager_join

Put thread creation and join under lock
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 66f201c..e4e7c47 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -2,17 +2,20 @@
 # Uses OWNERS files in different modules throughout the
 # repository as the source of truth for module ownership.
 /** @a11r @nicolasnoble @ctiller
-/binding.gyp @murgatroid99
-/Gemfile @murgatroid99
-/grpc.gemspec @murgatroid99
-/package.json @murgatroid99
-/Rakefile @murgatroid99
+/*.podspec @muxi @makdharma @a11r @nicolasnoble @ctiller
+/binding.gyp @murgatroid99 @a11r @nicolasnoble @ctiller
+/Gemfile @murgatroid99 @a11r @nicolasnoble @ctiller
+/grpc.gemspec @murgatroid99 @a11r @nicolasnoble @ctiller
+/package.json @murgatroid99 @a11r @nicolasnoble @ctiller
+/Rakefile @murgatroid99 @a11r @nicolasnoble @ctiller
+/grpc.bzl @muxi @makdharma @a11r @nicolasnoble @ctiller
 /bazel/** @nicolasnoble @dgquintas @ctiller
 /cmake/** @jtattermusch @a11r @nicolasnoble @ctiller
 /doc/PROTOCOL-HTTP2.md @ejona86 @a11r @nicolasnoble @ctiller
 /doc/interop-test-descriptions.md @ejona86 @a11r @nicolasnoble @ctiller
 /etc/** @jboeuf @nicolasnoble @a11r @ctiller
 /examples/node/** @murgatroid99 @a11r @nicolasnoble @ctiller
+/examples/objective-c/** @muxi @makdharma @a11r @nicolasnoble @ctiller
 /examples/python/** @nathanielmanistaatgoogle @kpayson64 @mehrdada
 /include/** @ctiller @markdroth @dgquintas @a11r @nicolasnoble
 /src/core/** @ctiller @markdroth @dgquintas
@@ -34,7 +37,5 @@
 /tools/** @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller
 /tools/codegen/core/** @ctiller @dgquintas @markdroth
 /tools/distrib/python/** @nathanielmanistaatgoogle @kpayson64 @mehrdada
-/tools/dockerfile/** @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller
-/tools/run_tests/** @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller
 /tools/run_tests/artifacts/*_node* @murgatroid99 @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller
 /tools/run_tests/helper_scripts/*_node* @murgatroid99 @matt-kwong @jtattermusch @nicolasnoble @a11r @ctiller
diff --git a/BUILD b/BUILD
index 26981ca..6f92ef3 100644
--- a/BUILD
+++ b/BUILD
@@ -837,6 +837,7 @@
         "grpc_resolver_sockaddr",
         "grpc_transport_chttp2_client_insecure",
         "grpc_transport_chttp2_server_insecure",
+        "grpc_transport_inproc",
         "grpc_workaround_cronet_compression_filter",
         "grpc_server_backward_compatibility",
     ],
@@ -1383,6 +1384,21 @@
 )
 
 grpc_cc_library(
+    name = "grpc_transport_inproc",
+    srcs = [
+        "src/core/ext/transport/inproc/inproc_plugin.c",
+        "src/core/ext/transport/inproc/inproc_transport.c",
+    ],
+    hdrs = [
+        "src/core/ext/transport/inproc/inproc_transport.h",
+    ],
+    language = "c",
+    deps = [
+        "grpc_base",
+    ],
+)
+
+grpc_cc_library(
     name = "tsi",
     srcs = [
         "src/core/tsi/fake_transport_security.c",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3dd8ec4..6ee9490 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -599,6 +599,7 @@
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_c h2_uds_test)
 endif()
+add_dependencies(buildtests_c inproc_test)
 add_dependencies(buildtests_c h2_census_nosec_test)
 add_dependencies(buildtests_c h2_compress_nosec_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -619,6 +620,7 @@
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_c h2_uds_nosec_test)
 endif()
+add_dependencies(buildtests_c inproc_nosec_test)
 add_dependencies(buildtests_c api_fuzzer_one_entry)
 add_dependencies(buildtests_c client_fuzzer_one_entry)
 add_dependencies(buildtests_c hpack_parser_fuzzer_test_one_entry)
@@ -1151,6 +1153,8 @@
   src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
   src/core/ext/transport/chttp2/client/insecure/channel_create.c
   src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c
+  src/core/ext/transport/inproc/inproc_plugin.c
+  src/core/ext/transport/inproc/inproc_transport.c
   src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c
   src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c
   src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c
@@ -2041,6 +2045,8 @@
   src/core/ext/filters/client_channel/subchannel_index.c
   src/core/ext/filters/client_channel/uri_parser.c
   src/core/ext/filters/deadline/deadline_filter.c
+  src/core/ext/transport/inproc/inproc_plugin.c
+  src/core/ext/transport/inproc/inproc_transport.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c
   src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c
@@ -13357,6 +13363,38 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(inproc_test
+  test/core/end2end/fixtures/inproc.c
+)
+
+
+target_include_directories(inproc_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(inproc_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_census_nosec_test
   test/core/end2end/fixtures/h2_census.c
 )
@@ -13811,6 +13849,38 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(inproc_nosec_test
+  test/core/end2end/fixtures/inproc.c
+)
+
+
+target_include_directories(inproc_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(inproc_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(api_fuzzer_one_entry
   test/core/end2end/fuzzers/api_fuzzer.c
   test/core/util/one_corpus_entry_fuzzer.c
diff --git a/Makefile b/Makefile
index f58a02d..72468f8 100644
--- a/Makefile
+++ b/Makefile
@@ -1243,6 +1243,7 @@
 h2_ssl_cert_test: $(BINDIR)/$(CONFIG)/h2_ssl_cert_test
 h2_ssl_proxy_test: $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test
 h2_uds_test: $(BINDIR)/$(CONFIG)/h2_uds_test
+inproc_test: $(BINDIR)/$(CONFIG)/inproc_test
 h2_census_nosec_test: $(BINDIR)/$(CONFIG)/h2_census_nosec_test
 h2_compress_nosec_test: $(BINDIR)/$(CONFIG)/h2_compress_nosec_test
 h2_fd_nosec_test: $(BINDIR)/$(CONFIG)/h2_fd_nosec_test
@@ -1257,6 +1258,7 @@
 h2_sockpair+trace_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test
 h2_sockpair_1byte_nosec_test: $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_nosec_test
 h2_uds_nosec_test: $(BINDIR)/$(CONFIG)/h2_uds_nosec_test
+inproc_nosec_test: $(BINDIR)/$(CONFIG)/inproc_nosec_test
 api_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/api_fuzzer_one_entry
 client_fuzzer_one_entry: $(BINDIR)/$(CONFIG)/client_fuzzer_one_entry
 hpack_parser_fuzzer_test_one_entry: $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test_one_entry
@@ -1492,6 +1494,7 @@
   $(BINDIR)/$(CONFIG)/h2_ssl_cert_test \
   $(BINDIR)/$(CONFIG)/h2_ssl_proxy_test \
   $(BINDIR)/$(CONFIG)/h2_uds_test \
+  $(BINDIR)/$(CONFIG)/inproc_test \
   $(BINDIR)/$(CONFIG)/h2_census_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_compress_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_fd_nosec_test \
@@ -1506,6 +1509,7 @@
   $(BINDIR)/$(CONFIG)/h2_sockpair+trace_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_sockpair_1byte_nosec_test \
   $(BINDIR)/$(CONFIG)/h2_uds_nosec_test \
+  $(BINDIR)/$(CONFIG)/inproc_nosec_test \
   $(BINDIR)/$(CONFIG)/api_fuzzer_one_entry \
   $(BINDIR)/$(CONFIG)/client_fuzzer_one_entry \
   $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test_one_entry \
@@ -3086,6 +3090,8 @@
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
+    src/core/ext/transport/inproc/inproc_plugin.c \
+    src/core/ext/transport/inproc/inproc_transport.c \
     src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c \
     src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c \
     src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c \
@@ -3943,6 +3949,8 @@
     src/core/ext/filters/client_channel/subchannel_index.c \
     src/core/ext/filters/client_channel/uri_parser.c \
     src/core/ext/filters/deadline/deadline_filter.c \
+    src/core/ext/transport/inproc/inproc_plugin.c \
+    src/core/ext/transport/inproc/inproc_transport.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c \
     src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c \
@@ -18297,6 +18305,38 @@
 endif
 
 
+INPROC_TEST_SRC = \
+    test/core/end2end/fixtures/inproc.c \
+
+INPROC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INPROC_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/inproc_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/inproc_test: $(INPROC_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) $(INPROC_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)/inproc_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/inproc.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_inproc_test: $(INPROC_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(INPROC_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 H2_CENSUS_NOSEC_TEST_SRC = \
     test/core/end2end/fixtures/h2_census.c \
 
@@ -18577,6 +18617,26 @@
 endif
 
 
+INPROC_NOSEC_TEST_SRC = \
+    test/core/end2end/fixtures/inproc.c \
+
+INPROC_NOSEC_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INPROC_NOSEC_TEST_SRC))))
+
+
+$(BINDIR)/$(CONFIG)/inproc_nosec_test: $(INPROC_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) $(INPROC_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)/inproc_nosec_test
+
+$(OBJDIR)/$(CONFIG)/test/core/end2end/fixtures/inproc.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_inproc_nosec_test: $(INPROC_NOSEC_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_DEPS),true)
+-include $(INPROC_NOSEC_TEST_OBJS:.o=.dep)
+endif
+
+
 API_FUZZER_ONE_ENTRY_SRC = \
     test/core/end2end/fuzzers/api_fuzzer.c \
     test/core/util/one_corpus_entry_fuzzer.c \
diff --git a/OWNERS b/OWNERS
index 87958a4..7e6a84c 100644
--- a/OWNERS
+++ b/OWNERS
@@ -5,3 +5,5 @@
 @ctiller
 
 @murgatroid99 binding.gyp Gemfile grpc.gemspec package.json Rakefile
+@muxi *.podspec grpc.bzl
+@makdharma *.podspec grpc.bzl
diff --git a/binding.gyp b/binding.gyp
index 0b581b3..00fbe70 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -844,6 +844,8 @@
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
         'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
         'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+        'src/core/ext/transport/inproc/inproc_plugin.c',
+        'src/core/ext/transport/inproc/inproc_transport.c',
         'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c',
         'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
         'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
diff --git a/build.yaml b/build.yaml
index 8a2fbe1..1b9eb63 100644
--- a/build.yaml
+++ b/build.yaml
@@ -843,6 +843,15 @@
   - grpc_base
   - grpc_transport_chttp2
   - grpc_http_filters
+- name: grpc_transport_inproc
+  headers:
+  - src/core/ext/transport/inproc/inproc_transport.h
+  src:
+  - src/core/ext/transport/inproc/inproc_plugin.c
+  - src/core/ext/transport/inproc/inproc_transport.c
+  plugin: grpc_inproc_plugin
+  uses:
+  - grpc_base
 - name: grpc_workaround_cronet_compression_filter
   headers:
   - src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
@@ -1071,6 +1080,7 @@
   - grpc_transport_chttp2_client_secure
   - grpc_transport_chttp2_server_insecure
   - grpc_transport_chttp2_client_insecure
+  - grpc_transport_inproc
   - grpc_lb_policy_grpclb_secure
   - grpc_lb_policy_pick_first
   - grpc_lb_policy_round_robin
@@ -1174,6 +1184,7 @@
   - grpc_base
   - grpc_transport_chttp2_server_insecure
   - grpc_transport_chttp2_client_insecure
+  - grpc_transport_inproc
   - grpc_resolver_dns_ares
   - grpc_resolver_dns_native
   - grpc_resolver_sockaddr
diff --git a/config.m4 b/config.m4
index d3a5dc4..71e5776 100644
--- a/config.m4
+++ b/config.m4
@@ -294,6 +294,8 @@
     src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create.c \
     src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c \
+    src/core/ext/transport/inproc/inproc_plugin.c \
+    src/core/ext/transport/inproc/inproc_transport.c \
     src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c \
     src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c \
     src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c \
@@ -673,6 +675,7 @@
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport)
+  PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/inproc)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression)
   PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug)
diff --git a/config.w32 b/config.w32
index a1f6d03..cd374ba 100644
--- a/config.w32
+++ b/config.w32
@@ -271,6 +271,8 @@
     "src\\core\\ext\\transport\\chttp2\\server\\insecure\\server_chttp2_posix.c " +
     "src\\core\\ext\\transport\\chttp2\\client\\insecure\\channel_create.c " +
     "src\\core\\ext\\transport\\chttp2\\client\\insecure\\channel_create_posix.c " +
+    "src\\core\\ext\\transport\\inproc\\inproc_plugin.c " +
+    "src\\core\\ext\\transport\\inproc\\inproc_transport.c " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\client_load_reporting_filter.c " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb.c " +
     "src\\core\\ext\\filters\\client_channel\\lb_policy\\grpclb\\grpclb_channel_secure.c " +
@@ -685,6 +687,7 @@
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\chttp2\\server\\insecure");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\chttp2\\server\\secure");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\chttp2\\transport");
+  FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\transport\\inproc");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\channel");
   FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\lib\\compression");
diff --git a/examples/objective-c/OWNERS b/examples/objective-c/OWNERS
new file mode 100644
index 0000000..c14fe53
--- /dev/null
+++ b/examples/objective-c/OWNERS
@@ -0,0 +1,2 @@
+@muxi
+@makdharma
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 3f841d5..fc51a92 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -423,6 +423,7 @@
                       'src/core/ext/filters/client_channel/uri_parser.h',
                       'src/core/ext/filters/deadline/deadline_filter.h',
                       'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                      'src/core/ext/transport/inproc/inproc_transport.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
@@ -665,6 +666,8 @@
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
                       'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
                       'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+                      'src/core/ext/transport/inproc/inproc_plugin.c',
+                      'src/core/ext/transport/inproc/inproc_transport.c',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
                       'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
@@ -900,6 +903,7 @@
                               'src/core/ext/filters/client_channel/uri_parser.h',
                               'src/core/ext/filters/deadline/deadline_filter.h',
                               'src/core/ext/transport/chttp2/client/chttp2_connector.h',
+                              'src/core/ext/transport/inproc/inproc_transport.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h',
                               'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 663915b..ab4a634 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -355,6 +355,7 @@
   s.files += %w( src/core/ext/filters/client_channel/uri_parser.h )
   s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
   s.files += %w( src/core/ext/transport/chttp2/client/chttp2_connector.h )
+  s.files += %w( src/core/ext/transport/inproc/inproc_transport.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h )
@@ -601,6 +602,8 @@
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c )
   s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c )
   s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c )
+  s.files += %w( src/core/ext/transport/inproc/inproc_plugin.c )
+  s.files += %w( src/core/ext/transport/inproc/inproc_transport.c )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c )
   s.files += %w( src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c )
diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h
index 9d12003..cc9bf0a 100644
--- a/include/grpc++/impl/codegen/server_interface.h
+++ b/include/grpc++/impl/codegen/server_interface.h
@@ -28,6 +28,7 @@
 namespace grpc {
 
 class AsyncGenericService;
+class Channel;
 class GenericServerContext;
 class ServerCompletionQueue;
 class ServerContext;
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index 1ec9b97..92330d4 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -132,13 +132,17 @@
 /// services.
 std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
 
+/// Constant for maximum auth token lifetime.
+constexpr long kMaxAuthTokenLifetimeSecs = 3600;
+
 /// Builds Service Account JWT Access credentials.
 /// json_key is the JSON key string containing the client's private key.
 /// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
 /// (JWT) created with this credentials. It should not exceed
-/// \a grpc_max_auth_token_lifetime or will be cropped to this value.
+/// \a kMaxAuthTokenLifetimeSecs or will be cropped to this value.
 std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
-    const grpc::string& json_key, long token_lifetime_seconds);
+    const grpc::string& json_key,
+    long token_lifetime_seconds = kMaxAuthTokenLifetimeSecs);
 
 /// Builds refresh token credentials.
 /// json_refresh_token is the JSON string containing the refresh token along
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index baf0ded..4684b10 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -95,6 +95,9 @@
     return health_check_service_.get();
   }
 
+  /// Establish a channel for in-process communication
+  std::shared_ptr<Channel> InProcessChannel(const ChannelArguments& args);
+
  private:
   friend class AsyncGenericService;
   friend class ServerBuilder;
diff --git a/package.xml b/package.xml
index cfa45f0..602800b 100644
--- a/package.xml
+++ b/package.xml
@@ -369,6 +369,7 @@
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/uri_parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/chttp2_connector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" role="src" />
@@ -615,6 +616,8 @@
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_plugin.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/transport/inproc/inproc_transport.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c" role="src" />
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 0859ce8..bd25f69 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -1224,7 +1224,7 @@
 
 static void log_metadata(const grpc_metadata_batch *md_batch, uint32_t id,
                          bool is_client, bool is_initial) {
-  for (grpc_linked_mdelem *md = md_batch->list.head; md != md_batch->list.tail;
+  for (grpc_linked_mdelem *md = md_batch->list.head; md != NULL;
        md = md->next) {
     char *key = grpc_slice_to_c_string(GRPC_MDKEY(md->md));
     char *value = grpc_slice_to_c_string(GRPC_MDVALUE(md->md));
diff --git a/src/core/ext/transport/inproc/inproc_plugin.c b/src/core/ext/transport/inproc/inproc_plugin.c
new file mode 100644
index 0000000..6a796a0
--- /dev/null
+++ b/src/core/ext/transport/inproc/inproc_plugin.c
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/ext/transport/inproc/inproc_transport.h"
+#include "src/core/lib/debug/trace.h"
+
+grpc_tracer_flag grpc_inproc_trace = GRPC_TRACER_INITIALIZER(false, "inproc");
+
+void grpc_inproc_plugin_init(void) {
+  grpc_register_tracer(&grpc_inproc_trace);
+  grpc_inproc_transport_init();
+}
+
+void grpc_inproc_plugin_shutdown(void) { grpc_inproc_transport_shutdown(); }
diff --git a/src/core/ext/transport/inproc/inproc_transport.c b/src/core/ext/transport/inproc/inproc_transport.c
new file mode 100644
index 0000000..4df64d8
--- /dev/null
+++ b/src/core/ext/transport/inproc/inproc_transport.c
@@ -0,0 +1,1277 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/ext/transport/inproc/inproc_transport.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/time.h>
+#include <string.h>
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/surface/api_trace.h"
+#include "src/core/lib/surface/channel.h"
+#include "src/core/lib/surface/channel_stack_type.h"
+#include "src/core/lib/surface/server.h"
+#include "src/core/lib/transport/connectivity_state.h"
+#include "src/core/lib/transport/error_utils.h"
+#include "src/core/lib/transport/transport_impl.h"
+
+#define INPROC_LOG(...)                                          \
+  do {                                                           \
+    if (GRPC_TRACER_ON(grpc_inproc_trace)) gpr_log(__VA_ARGS__); \
+  } while (0)
+
+static const grpc_transport_vtable inproc_vtable;
+static grpc_slice g_empty_slice;
+static grpc_slice g_fake_path_key;
+static grpc_slice g_fake_path_value;
+static grpc_slice g_fake_auth_key;
+static grpc_slice g_fake_auth_value;
+
+typedef struct {
+  gpr_mu mu;
+  gpr_refcount refs;
+} shared_mu;
+
+typedef struct inproc_transport {
+  grpc_transport base;
+  shared_mu *mu;
+  gpr_refcount refs;
+  bool is_client;
+  grpc_connectivity_state_tracker connectivity;
+  void (*accept_stream_cb)(grpc_exec_ctx *exec_ctx, void *user_data,
+                           grpc_transport *transport, const void *server_data);
+  void *accept_stream_data;
+  bool is_closed;
+  struct inproc_transport *other_side;
+  struct inproc_stream *stream_list;
+} inproc_transport;
+
+typedef struct sb_list_entry {
+  grpc_slice_buffer sb;
+  struct sb_list_entry *next;
+} sb_list_entry;
+
+// Specialize grpc_byte_stream for our use case
+typedef struct {
+  grpc_byte_stream base;
+  sb_list_entry *le;
+} inproc_slice_byte_stream;
+
+typedef struct {
+  // TODO (vjpai): Add some inlined elements to avoid alloc in simple cases
+  sb_list_entry *head;
+  sb_list_entry *tail;
+} slice_buffer_list;
+
+static void slice_buffer_list_init(slice_buffer_list *l) {
+  l->head = NULL;
+  l->tail = NULL;
+}
+
+static void sb_list_entry_destroy(grpc_exec_ctx *exec_ctx, sb_list_entry *le) {
+  grpc_slice_buffer_destroy_internal(exec_ctx, &le->sb);
+  gpr_free(le);
+}
+
+static void slice_buffer_list_destroy(grpc_exec_ctx *exec_ctx,
+                                      slice_buffer_list *l) {
+  sb_list_entry *curr = l->head;
+  while (curr != NULL) {
+    sb_list_entry *le = curr;
+    curr = curr->next;
+    sb_list_entry_destroy(exec_ctx, le);
+  }
+  l->head = NULL;
+  l->tail = NULL;
+}
+
+static bool slice_buffer_list_empty(slice_buffer_list *l) {
+  return l->head == NULL;
+}
+
+static void slice_buffer_list_append_entry(slice_buffer_list *l,
+                                           sb_list_entry *next) {
+  next->next = NULL;
+  if (l->tail) {
+    l->tail->next = next;
+    l->tail = next;
+  } else {
+    l->head = next;
+    l->tail = next;
+  }
+}
+
+static grpc_slice_buffer *slice_buffer_list_append(slice_buffer_list *l) {
+  sb_list_entry *next = gpr_malloc(sizeof(*next));
+  grpc_slice_buffer_init(&next->sb);
+  slice_buffer_list_append_entry(l, next);
+  return &next->sb;
+}
+
+static sb_list_entry *slice_buffer_list_pophead(slice_buffer_list *l) {
+  sb_list_entry *ret = l->head;
+  l->head = l->head->next;
+  if (l->head == NULL) {
+    l->tail = NULL;
+  }
+  return ret;
+}
+
+typedef struct inproc_stream {
+  inproc_transport *t;
+  grpc_metadata_batch to_read_initial_md;
+  uint32_t to_read_initial_md_flags;
+  bool to_read_initial_md_filled;
+  slice_buffer_list to_read_message;
+  grpc_metadata_batch to_read_trailing_md;
+  bool to_read_trailing_md_filled;
+  bool reads_needed;
+  bool read_closure_scheduled;
+  grpc_closure read_closure;
+  // Write buffer used only during gap at init time when client-side
+  // stream is set up but server side stream is not yet set up
+  grpc_metadata_batch write_buffer_initial_md;
+  bool write_buffer_initial_md_filled;
+  uint32_t write_buffer_initial_md_flags;
+  gpr_timespec write_buffer_deadline;
+  slice_buffer_list write_buffer_message;
+  grpc_metadata_batch write_buffer_trailing_md;
+  bool write_buffer_trailing_md_filled;
+  grpc_error *write_buffer_cancel_error;
+
+  struct inproc_stream *other_side;
+  bool other_side_closed;               // won't talk anymore
+  bool write_buffer_other_side_closed;  // on hold
+  grpc_stream_refcount *refs;
+  grpc_closure *closure_at_destroy;
+
+  gpr_arena *arena;
+
+  grpc_transport_stream_op_batch *recv_initial_md_op;
+  grpc_transport_stream_op_batch *recv_message_op;
+  grpc_transport_stream_op_batch *recv_trailing_md_op;
+
+  inproc_slice_byte_stream recv_message_stream;
+
+  bool initial_md_sent;
+  bool trailing_md_sent;
+  bool initial_md_recvd;
+  bool trailing_md_recvd;
+
+  bool closed;
+
+  grpc_error *cancel_self_error;
+  grpc_error *cancel_other_error;
+
+  gpr_timespec deadline;
+
+  bool listed;
+  struct inproc_stream *stream_list_prev;
+  struct inproc_stream *stream_list_next;
+} inproc_stream;
+
+static bool inproc_slice_byte_stream_next(grpc_exec_ctx *exec_ctx,
+                                          grpc_byte_stream *bs, size_t max,
+                                          grpc_closure *on_complete) {
+  inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs;
+  return (stream->le->sb.count != 0);
+}
+
+static grpc_error *inproc_slice_byte_stream_pull(grpc_exec_ctx *exec_ctx,
+                                                 grpc_byte_stream *bs,
+                                                 grpc_slice *slice) {
+  inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs;
+  *slice = grpc_slice_buffer_take_first(&stream->le->sb);
+  return GRPC_ERROR_NONE;
+}
+
+static void inproc_slice_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
+                                             grpc_byte_stream *bs) {
+  inproc_slice_byte_stream *stream = (inproc_slice_byte_stream *)bs;
+  sb_list_entry_destroy(exec_ctx, stream->le);
+}
+
+void inproc_slice_byte_stream_init(inproc_slice_byte_stream *s,
+                                   sb_list_entry *le) {
+  s->base.length = (uint32_t)le->sb.length;
+  s->base.flags = 0;
+  s->base.next = inproc_slice_byte_stream_next;
+  s->base.pull = inproc_slice_byte_stream_pull;
+  s->base.destroy = inproc_slice_byte_stream_destroy;
+  s->le = le;
+}
+
+static void ref_transport(inproc_transport *t) {
+  INPROC_LOG(GPR_DEBUG, "ref_transport %p", t);
+  gpr_ref(&t->refs);
+}
+
+static void really_destroy_transport(grpc_exec_ctx *exec_ctx,
+                                     inproc_transport *t) {
+  INPROC_LOG(GPR_DEBUG, "really_destroy_transport %p", t);
+  grpc_connectivity_state_destroy(exec_ctx, &t->connectivity);
+  if (gpr_unref(&t->mu->refs)) {
+    gpr_free(t->mu);
+  }
+  gpr_free(t);
+}
+
+static void unref_transport(grpc_exec_ctx *exec_ctx, inproc_transport *t) {
+  INPROC_LOG(GPR_DEBUG, "unref_transport %p", t);
+  if (gpr_unref(&t->refs)) {
+    really_destroy_transport(exec_ctx, t);
+  }
+}
+
+#ifndef NDEBUG
+#define STREAM_REF(refs, reason) grpc_stream_ref(refs, reason)
+#define STREAM_UNREF(e, refs, reason) grpc_stream_unref(e, refs, reason)
+#else
+#define STREAM_REF(refs, reason) grpc_stream_ref(refs)
+#define STREAM_UNREF(e, refs, reason) grpc_stream_unref(e, refs)
+#endif
+
+static void ref_stream(inproc_stream *s, const char *reason) {
+  INPROC_LOG(GPR_DEBUG, "ref_stream %p %s", s, reason);
+  STREAM_REF(s->refs, reason);
+}
+
+static void unref_stream(grpc_exec_ctx *exec_ctx, inproc_stream *s,
+                         const char *reason) {
+  INPROC_LOG(GPR_DEBUG, "unref_stream %p %s", s, reason);
+  STREAM_UNREF(exec_ctx, s->refs, reason);
+}
+
+static void really_destroy_stream(grpc_exec_ctx *exec_ctx, inproc_stream *s) {
+  INPROC_LOG(GPR_DEBUG, "really_destroy_stream %p", s);
+
+  slice_buffer_list_destroy(exec_ctx, &s->to_read_message);
+  slice_buffer_list_destroy(exec_ctx, &s->write_buffer_message);
+  GRPC_ERROR_UNREF(s->write_buffer_cancel_error);
+  GRPC_ERROR_UNREF(s->cancel_self_error);
+  GRPC_ERROR_UNREF(s->cancel_other_error);
+
+  unref_transport(exec_ctx, s->t);
+
+  if (s->closure_at_destroy) {
+    GRPC_CLOSURE_SCHED(exec_ctx, s->closure_at_destroy, GRPC_ERROR_NONE);
+  }
+}
+
+static void read_state_machine(grpc_exec_ctx *exec_ctx, void *arg,
+                               grpc_error *error);
+
+static void log_metadata(const grpc_metadata_batch *md_batch, bool is_client,
+                         bool is_initial) {
+  for (grpc_linked_mdelem *md = md_batch->list.head; md != NULL;
+       md = md->next) {
+    char *key = grpc_slice_to_c_string(GRPC_MDKEY(md->md));
+    char *value = grpc_slice_to_c_string(GRPC_MDVALUE(md->md));
+    gpr_log(GPR_INFO, "INPROC:%s:%s: %s: %s", is_initial ? "HDR" : "TRL",
+            is_client ? "CLI" : "SVR", key, value);
+    gpr_free(key);
+    gpr_free(value);
+  }
+}
+
+static grpc_error *fill_in_metadata(grpc_exec_ctx *exec_ctx, inproc_stream *s,
+                                    const grpc_metadata_batch *metadata,
+                                    uint32_t flags, grpc_metadata_batch *out_md,
+                                    uint32_t *outflags, bool *markfilled) {
+  if (GRPC_TRACER_ON(grpc_inproc_trace)) {
+    log_metadata(metadata, s->t->is_client, outflags != NULL);
+  }
+
+  if (outflags != NULL) {
+    *outflags = flags;
+  }
+  if (markfilled != NULL) {
+    *markfilled = true;
+  }
+  grpc_error *error = GRPC_ERROR_NONE;
+  for (grpc_linked_mdelem *elem = metadata->list.head;
+       (elem != NULL) && (error == GRPC_ERROR_NONE); elem = elem->next) {
+    grpc_linked_mdelem *nelem = gpr_arena_alloc(s->arena, sizeof(*nelem));
+    nelem->md = grpc_mdelem_from_slices(
+        exec_ctx, grpc_slice_intern(GRPC_MDKEY(elem->md)),
+        grpc_slice_intern(GRPC_MDVALUE(elem->md)));
+
+    error = grpc_metadata_batch_link_tail(exec_ctx, out_md, nelem);
+  }
+  return error;
+}
+
+static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                       grpc_stream *gs, grpc_stream_refcount *refcount,
+                       const void *server_data, gpr_arena *arena) {
+  INPROC_LOG(GPR_DEBUG, "init_stream %p %p %p", gt, gs, server_data);
+  inproc_transport *t = (inproc_transport *)gt;
+  inproc_stream *s = (inproc_stream *)gs;
+  s->arena = arena;
+
+  s->refs = refcount;
+  // Ref this stream right now
+  ref_stream(s, "inproc_init_stream:init");
+
+  grpc_metadata_batch_init(&s->to_read_initial_md);
+  s->to_read_initial_md_flags = 0;
+  s->to_read_initial_md_filled = false;
+  grpc_metadata_batch_init(&s->to_read_trailing_md);
+  s->to_read_trailing_md_filled = false;
+  grpc_metadata_batch_init(&s->write_buffer_initial_md);
+  s->write_buffer_initial_md_flags = 0;
+  s->write_buffer_initial_md_filled = false;
+  grpc_metadata_batch_init(&s->write_buffer_trailing_md);
+  s->write_buffer_trailing_md_filled = false;
+  slice_buffer_list_init(&s->to_read_message);
+  slice_buffer_list_init(&s->write_buffer_message);
+  s->reads_needed = false;
+  s->read_closure_scheduled = false;
+  GRPC_CLOSURE_INIT(&s->read_closure, read_state_machine, s,
+                    grpc_schedule_on_exec_ctx);
+  s->t = t;
+  s->closure_at_destroy = NULL;
+  s->other_side_closed = false;
+
+  s->initial_md_sent = s->trailing_md_sent = s->initial_md_recvd =
+      s->trailing_md_recvd = false;
+
+  s->closed = false;
+
+  s->cancel_self_error = GRPC_ERROR_NONE;
+  s->cancel_other_error = GRPC_ERROR_NONE;
+  s->write_buffer_cancel_error = GRPC_ERROR_NONE;
+  s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  s->write_buffer_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+
+  s->stream_list_prev = NULL;
+  gpr_mu_lock(&t->mu->mu);
+  s->listed = true;
+  ref_stream(s, "inproc_init_stream:list");
+  s->stream_list_next = t->stream_list;
+  if (t->stream_list) {
+    t->stream_list->stream_list_prev = s;
+  }
+  t->stream_list = s;
+  gpr_mu_unlock(&t->mu->mu);
+
+  if (!server_data) {
+    ref_transport(t);
+    inproc_transport *st = t->other_side;
+    ref_transport(st);
+    s->other_side = NULL;  // will get filled in soon
+    // Pass the client-side stream address to the server-side for a ref
+    ref_stream(s, "inproc_init_stream:clt");  // ref it now on behalf of server
+                                              // side to avoid destruction
+    INPROC_LOG(GPR_DEBUG, "calling accept stream cb %p %p",
+               st->accept_stream_cb, st->accept_stream_data);
+    (*st->accept_stream_cb)(exec_ctx, st->accept_stream_data, &st->base,
+                            (void *)s);
+  } else {
+    // This is the server-side and is being called through accept_stream_cb
+    inproc_stream *cs = (inproc_stream *)server_data;
+    s->other_side = cs;
+    // Ref the server-side stream on behalf of the client now
+    ref_stream(s, "inproc_init_stream:srv");
+
+    // Now we are about to affect the other side, so lock the transport
+    // to make sure that it doesn't get destroyed
+    gpr_mu_lock(&s->t->mu->mu);
+    cs->other_side = s;
+    // Now transfer from the other side's write_buffer if any to the to_read
+    // buffer
+    if (cs->write_buffer_initial_md_filled) {
+      fill_in_metadata(exec_ctx, s, &cs->write_buffer_initial_md,
+                       cs->write_buffer_initial_md_flags,
+                       &s->to_read_initial_md, &s->to_read_initial_md_flags,
+                       &s->to_read_initial_md_filled);
+      s->deadline = gpr_time_min(s->deadline, cs->write_buffer_deadline);
+      grpc_metadata_batch_clear(exec_ctx, &cs->write_buffer_initial_md);
+      cs->write_buffer_initial_md_filled = false;
+    }
+    while (!slice_buffer_list_empty(&cs->write_buffer_message)) {
+      slice_buffer_list_append_entry(
+          &s->to_read_message,
+          slice_buffer_list_pophead(&cs->write_buffer_message));
+    }
+    if (cs->write_buffer_trailing_md_filled) {
+      fill_in_metadata(exec_ctx, s, &cs->write_buffer_trailing_md, 0,
+                       &s->to_read_trailing_md, NULL,
+                       &s->to_read_trailing_md_filled);
+      grpc_metadata_batch_clear(exec_ctx, &cs->write_buffer_trailing_md);
+      cs->write_buffer_trailing_md_filled = false;
+    }
+    if (cs->write_buffer_cancel_error != GRPC_ERROR_NONE) {
+      s->cancel_other_error = cs->write_buffer_cancel_error;
+      cs->write_buffer_cancel_error = GRPC_ERROR_NONE;
+    }
+
+    gpr_mu_unlock(&s->t->mu->mu);
+  }
+  return 0;  // return value is not important
+}
+
+static void close_stream_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s) {
+  if (!s->closed) {
+    // Release the metadata that we would have written out
+    grpc_metadata_batch_destroy(exec_ctx, &s->write_buffer_initial_md);
+    grpc_metadata_batch_destroy(exec_ctx, &s->write_buffer_trailing_md);
+
+    if (s->listed) {
+      inproc_stream *p = s->stream_list_prev;
+      inproc_stream *n = s->stream_list_next;
+      if (p != NULL) {
+        p->stream_list_next = n;
+      } else {
+        s->t->stream_list = n;
+      }
+      if (n != NULL) {
+        n->stream_list_prev = p;
+      }
+      s->listed = false;
+      unref_stream(exec_ctx, s, "close_stream:list");
+    }
+    s->closed = true;
+    unref_stream(exec_ctx, s, "close_stream:closing");
+  }
+}
+
+// This function means that we are done talking/listening to the other side
+static void close_other_side_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s,
+                                    const char *reason) {
+  if (s->other_side != NULL) {
+    // First release the metadata that came from the other side's arena
+    grpc_metadata_batch_destroy(exec_ctx, &s->to_read_initial_md);
+    grpc_metadata_batch_destroy(exec_ctx, &s->to_read_trailing_md);
+
+    unref_stream(exec_ctx, s->other_side, reason);
+    s->other_side_closed = true;
+    s->other_side = NULL;
+  } else if (!s->other_side_closed) {
+    s->write_buffer_other_side_closed = true;
+  }
+}
+
+static void fail_helper_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s,
+                               grpc_error *error) {
+  INPROC_LOG(GPR_DEBUG, "read_state_machine %p fail_helper", s);
+  // If we're failing this side, we need to make sure that
+  // we also send or have already sent trailing metadata
+  if (!s->trailing_md_sent) {
+    // Send trailing md to the other side indicating cancellation
+    s->trailing_md_sent = true;
+
+    grpc_metadata_batch fake_md;
+    grpc_metadata_batch_init(&fake_md);
+
+    inproc_stream *other = s->other_side;
+    grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md
+                                                : &other->to_read_trailing_md;
+    bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled
+                                       : &other->to_read_trailing_md_filled;
+    fill_in_metadata(exec_ctx, s, &fake_md, 0, dest, NULL, destfilled);
+    grpc_metadata_batch_destroy(exec_ctx, &fake_md);
+
+    if (other != NULL) {
+      if (other->cancel_other_error == GRPC_ERROR_NONE) {
+        other->cancel_other_error = GRPC_ERROR_REF(error);
+      }
+      if (other->reads_needed) {
+        if (!other->read_closure_scheduled) {
+          GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure,
+                             GRPC_ERROR_REF(error));
+          other->read_closure_scheduled = true;
+        }
+        other->reads_needed = false;
+      }
+    } else if (s->write_buffer_cancel_error == GRPC_ERROR_NONE) {
+      s->write_buffer_cancel_error = GRPC_ERROR_REF(error);
+    }
+  }
+  if (s->recv_initial_md_op) {
+    grpc_error *err;
+    if (!s->t->is_client) {
+      // If this is a server, provide initial metadata with a path and authority
+      // since it expects that as well as no error yet
+      grpc_metadata_batch fake_md;
+      grpc_metadata_batch_init(&fake_md);
+      grpc_linked_mdelem *path_md = gpr_arena_alloc(s->arena, sizeof(*path_md));
+      path_md->md =
+          grpc_mdelem_from_slices(exec_ctx, g_fake_path_key, g_fake_path_value);
+      GPR_ASSERT(grpc_metadata_batch_link_tail(exec_ctx, &fake_md, path_md) ==
+                 GRPC_ERROR_NONE);
+      grpc_linked_mdelem *auth_md = gpr_arena_alloc(s->arena, sizeof(*auth_md));
+      auth_md->md =
+          grpc_mdelem_from_slices(exec_ctx, g_fake_auth_key, g_fake_auth_value);
+      GPR_ASSERT(grpc_metadata_batch_link_tail(exec_ctx, &fake_md, auth_md) ==
+                 GRPC_ERROR_NONE);
+
+      fill_in_metadata(
+          exec_ctx, s, &fake_md, 0,
+          s->recv_initial_md_op->payload->recv_initial_metadata
+              .recv_initial_metadata,
+          s->recv_initial_md_op->payload->recv_initial_metadata.recv_flags,
+          NULL);
+      grpc_metadata_batch_destroy(exec_ctx, &fake_md);
+      err = GRPC_ERROR_NONE;
+    } else {
+      err = GRPC_ERROR_REF(error);
+    }
+    INPROC_LOG(GPR_DEBUG,
+               "fail_helper %p scheduling initial-metadata-ready %p %p", s,
+               error, err);
+    GRPC_CLOSURE_SCHED(exec_ctx,
+                       s->recv_initial_md_op->payload->recv_initial_metadata
+                           .recv_initial_metadata_ready,
+                       err);
+    // Last use of err so no need to REF and then UNREF it
+
+    if ((s->recv_initial_md_op != s->recv_message_op) &&
+        (s->recv_initial_md_op != s->recv_trailing_md_op)) {
+      INPROC_LOG(GPR_DEBUG,
+                 "fail_helper %p scheduling initial-metadata-on-complete %p",
+                 error, s);
+      GRPC_CLOSURE_SCHED(exec_ctx, s->recv_initial_md_op->on_complete,
+                         GRPC_ERROR_REF(error));
+    }
+    s->recv_initial_md_op = NULL;
+  }
+  if (s->recv_message_op) {
+    INPROC_LOG(GPR_DEBUG, "fail_helper %p scheduling message-ready %p", s,
+               error);
+    GRPC_CLOSURE_SCHED(
+        exec_ctx, s->recv_message_op->payload->recv_message.recv_message_ready,
+        GRPC_ERROR_REF(error));
+    if (s->recv_message_op != s->recv_trailing_md_op) {
+      INPROC_LOG(GPR_DEBUG, "fail_helper %p scheduling message-on-complete %p",
+                 s, error);
+      GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete,
+                         GRPC_ERROR_REF(error));
+    }
+    s->recv_message_op = NULL;
+  }
+  if (s->recv_trailing_md_op) {
+    INPROC_LOG(GPR_DEBUG,
+               "fail_helper %p scheduling trailing-md-on-complete %p", s,
+               error);
+    GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete,
+                       GRPC_ERROR_REF(error));
+    s->recv_trailing_md_op = NULL;
+  }
+  close_other_side_locked(exec_ctx, s, "fail_helper:other_side");
+  close_stream_locked(exec_ctx, s);
+
+  GRPC_ERROR_UNREF(error);
+}
+
+static void read_state_machine(grpc_exec_ctx *exec_ctx, void *arg,
+                               grpc_error *error) {
+  // This function gets called when we have contents in the unprocessed reads
+  // Get what we want based on our ops wanted
+  // Schedule our appropriate closures
+  // and then return to reads_needed state if still needed
+
+  // Since this is a closure directly invoked by the combiner, it should not
+  // unref the error parameter explicitly; the combiner will do that implicitly
+  grpc_error *new_err = GRPC_ERROR_NONE;
+
+  bool needs_close = false;
+
+  INPROC_LOG(GPR_DEBUG, "read_state_machine %p", arg);
+  inproc_stream *s = (inproc_stream *)arg;
+  gpr_mu *mu = &s->t->mu->mu;  // keep aside in case s gets closed
+  gpr_mu_lock(mu);
+  s->read_closure_scheduled = false;
+  // cancellation takes precedence
+  if (s->cancel_self_error != GRPC_ERROR_NONE) {
+    fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(s->cancel_self_error));
+    goto done;
+  } else if (s->cancel_other_error != GRPC_ERROR_NONE) {
+    fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(s->cancel_other_error));
+    goto done;
+  } else if (error != GRPC_ERROR_NONE) {
+    fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(error));
+    goto done;
+  }
+
+  if (s->recv_initial_md_op) {
+    if (!s->to_read_initial_md_filled) {
+      // We entered the state machine on some other kind of read even though
+      // we still haven't satisfied initial md . That's an error.
+      new_err =
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unexpected frame sequencing");
+      INPROC_LOG(GPR_DEBUG,
+                 "read_state_machine %p scheduling on_complete errors for no "
+                 "initial md %p",
+                 s, new_err);
+      fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err));
+      goto done;
+    } else if (s->initial_md_recvd) {
+      new_err =
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Already recvd initial md");
+      INPROC_LOG(
+          GPR_DEBUG,
+          "read_state_machine %p scheduling on_complete errors for already "
+          "recvd initial md %p",
+          s, new_err);
+      fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err));
+      goto done;
+    }
+
+    s->initial_md_recvd = true;
+    new_err = fill_in_metadata(
+        exec_ctx, s, &s->to_read_initial_md, s->to_read_initial_md_flags,
+        s->recv_initial_md_op->payload->recv_initial_metadata
+            .recv_initial_metadata,
+        s->recv_initial_md_op->payload->recv_initial_metadata.recv_flags, NULL);
+    s->recv_initial_md_op->payload->recv_initial_metadata.recv_initial_metadata
+        ->deadline = s->deadline;
+    grpc_metadata_batch_clear(exec_ctx, &s->to_read_initial_md);
+    s->to_read_initial_md_filled = false;
+    INPROC_LOG(GPR_DEBUG,
+               "read_state_machine %p scheduling initial-metadata-ready %p", s,
+               new_err);
+    GRPC_CLOSURE_SCHED(exec_ctx,
+                       s->recv_initial_md_op->payload->recv_initial_metadata
+                           .recv_initial_metadata_ready,
+                       GRPC_ERROR_REF(new_err));
+    if ((s->recv_initial_md_op != s->recv_message_op) &&
+        (s->recv_initial_md_op != s->recv_trailing_md_op)) {
+      INPROC_LOG(
+          GPR_DEBUG,
+          "read_state_machine %p scheduling initial-metadata-on-complete %p", s,
+          new_err);
+      GRPC_CLOSURE_SCHED(exec_ctx, s->recv_initial_md_op->on_complete,
+                         GRPC_ERROR_REF(new_err));
+    }
+    s->recv_initial_md_op = NULL;
+
+    if (new_err != GRPC_ERROR_NONE) {
+      INPROC_LOG(GPR_DEBUG,
+                 "read_state_machine %p scheduling on_complete errors2 %p", s,
+                 new_err);
+      fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err));
+      goto done;
+    }
+  }
+  if (s->to_read_initial_md_filled) {
+    new_err = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Unexpected recv frame");
+    fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err));
+    goto done;
+  }
+  if (!slice_buffer_list_empty(&s->to_read_message) && s->recv_message_op) {
+    inproc_slice_byte_stream_init(
+        &s->recv_message_stream,
+        slice_buffer_list_pophead(&s->to_read_message));
+    *s->recv_message_op->payload->recv_message.recv_message =
+        &s->recv_message_stream.base;
+    INPROC_LOG(GPR_DEBUG, "read_state_machine %p scheduling message-ready", s);
+    GRPC_CLOSURE_SCHED(
+        exec_ctx, s->recv_message_op->payload->recv_message.recv_message_ready,
+        GRPC_ERROR_NONE);
+    if (s->recv_message_op != s->recv_trailing_md_op) {
+      INPROC_LOG(GPR_DEBUG,
+                 "read_state_machine %p scheduling message-on-complete %p", s,
+                 new_err);
+      GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete,
+                         GRPC_ERROR_REF(new_err));
+    }
+    s->recv_message_op = NULL;
+  }
+  if (s->to_read_trailing_md_filled) {
+    if (s->trailing_md_recvd) {
+      new_err =
+          GRPC_ERROR_CREATE_FROM_STATIC_STRING("Already recvd trailing md");
+      INPROC_LOG(
+          GPR_DEBUG,
+          "read_state_machine %p scheduling on_complete errors for already "
+          "recvd trailing md %p",
+          s, new_err);
+      fail_helper_locked(exec_ctx, s, GRPC_ERROR_REF(new_err));
+      goto done;
+    }
+    if (s->recv_message_op != NULL) {
+      // This message needs to be wrapped up because it will never be
+      // satisfied
+      INPROC_LOG(GPR_DEBUG, "read_state_machine %p scheduling message-ready",
+                 s);
+      GRPC_CLOSURE_SCHED(
+          exec_ctx,
+          s->recv_message_op->payload->recv_message.recv_message_ready,
+          GRPC_ERROR_NONE);
+      if (s->recv_message_op != s->recv_trailing_md_op) {
+        INPROC_LOG(GPR_DEBUG,
+                   "read_state_machine %p scheduling message-on-complete %p", s,
+                   new_err);
+        GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete,
+                           GRPC_ERROR_REF(new_err));
+      }
+      s->recv_message_op = NULL;
+    }
+    if (s->recv_trailing_md_op != NULL) {
+      // We wanted trailing metadata and we got it
+      s->trailing_md_recvd = true;
+      new_err =
+          fill_in_metadata(exec_ctx, s, &s->to_read_trailing_md, 0,
+                           s->recv_trailing_md_op->payload
+                               ->recv_trailing_metadata.recv_trailing_metadata,
+                           NULL, NULL);
+      grpc_metadata_batch_clear(exec_ctx, &s->to_read_trailing_md);
+      s->to_read_trailing_md_filled = false;
+
+      // We should schedule the recv_trailing_md_op completion if
+      // 1. this stream is the client-side
+      // 2. this stream is the server-side AND has already sent its trailing md
+      //    (If the server hasn't already sent its trailing md, it doesn't have
+      //     a final status, so don't mark this op complete)
+      if (s->t->is_client || s->trailing_md_sent) {
+        INPROC_LOG(
+            GPR_DEBUG,
+            "read_state_machine %p scheduling trailing-md-on-complete %p", s,
+            new_err);
+        GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete,
+                           GRPC_ERROR_REF(new_err));
+        s->recv_trailing_md_op = NULL;
+        needs_close = true;
+      } else {
+        INPROC_LOG(GPR_DEBUG,
+                   "read_state_machine %p server needs to delay handling "
+                   "trailing-md-on-complete %p",
+                   s, new_err);
+      }
+    } else {
+      INPROC_LOG(
+          GPR_DEBUG,
+          "read_state_machine %p has trailing md but not yet waiting for it",
+          s);
+    }
+  }
+  if (s->trailing_md_recvd && s->recv_message_op) {
+    // No further message will come on this stream, so finish off the
+    // recv_message_op
+    INPROC_LOG(GPR_DEBUG, "read_state_machine %p scheduling message-ready", s);
+    GRPC_CLOSURE_SCHED(
+        exec_ctx, s->recv_message_op->payload->recv_message.recv_message_ready,
+        GRPC_ERROR_NONE);
+    if (s->recv_message_op != s->recv_trailing_md_op) {
+      INPROC_LOG(GPR_DEBUG,
+                 "read_state_machine %p scheduling message-on-complete %p", s,
+                 new_err);
+      GRPC_CLOSURE_SCHED(exec_ctx, s->recv_message_op->on_complete,
+                         GRPC_ERROR_REF(new_err));
+    }
+    s->recv_message_op = NULL;
+  }
+  if (s->recv_message_op || s->recv_trailing_md_op) {
+    // Didn't get the item we wanted so we still need to get
+    // rescheduled
+    INPROC_LOG(GPR_DEBUG, "read_state_machine %p still needs closure %p %p", s,
+               s->recv_message_op, s->recv_trailing_md_op);
+    s->reads_needed = true;
+  }
+done:
+  if (needs_close) {
+    close_other_side_locked(exec_ctx, s, "read_state_machine");
+    close_stream_locked(exec_ctx, s);
+  }
+  gpr_mu_unlock(mu);
+  GRPC_ERROR_UNREF(new_err);
+}
+
+static grpc_closure do_nothing_closure;
+
+static bool cancel_stream_locked(grpc_exec_ctx *exec_ctx, inproc_stream *s,
+                                 grpc_error *error) {
+  bool ret = false;  // was the cancel accepted
+  INPROC_LOG(GPR_DEBUG, "cancel_stream %p with %s", s,
+             grpc_error_string(error));
+  if (s->cancel_self_error == GRPC_ERROR_NONE) {
+    ret = true;
+    s->cancel_self_error = GRPC_ERROR_REF(error);
+    if (s->reads_needed) {
+      if (!s->read_closure_scheduled) {
+        GRPC_CLOSURE_SCHED(exec_ctx, &s->read_closure,
+                           GRPC_ERROR_REF(s->cancel_self_error));
+        s->read_closure_scheduled = true;
+      }
+      s->reads_needed = false;
+    }
+    // Send trailing md to the other side indicating cancellation, even if we
+    // already have
+    s->trailing_md_sent = true;
+
+    grpc_metadata_batch cancel_md;
+    grpc_metadata_batch_init(&cancel_md);
+
+    inproc_stream *other = s->other_side;
+    grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md
+                                                : &other->to_read_trailing_md;
+    bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled
+                                       : &other->to_read_trailing_md_filled;
+    fill_in_metadata(exec_ctx, s, &cancel_md, 0, dest, NULL, destfilled);
+    grpc_metadata_batch_destroy(exec_ctx, &cancel_md);
+
+    if (other != NULL) {
+      if (other->cancel_other_error == GRPC_ERROR_NONE) {
+        other->cancel_other_error = GRPC_ERROR_REF(s->cancel_self_error);
+      }
+      if (other->reads_needed) {
+        if (!other->read_closure_scheduled) {
+          GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure,
+                             GRPC_ERROR_REF(other->cancel_other_error));
+          other->read_closure_scheduled = true;
+        }
+        other->reads_needed = false;
+      }
+    } else if (s->write_buffer_cancel_error == GRPC_ERROR_NONE) {
+      s->write_buffer_cancel_error = GRPC_ERROR_REF(s->cancel_self_error);
+    }
+
+    // if we are a server and already received trailing md but
+    // couldn't complete that because we hadn't yet sent out trailing
+    // md, now's the chance
+    if (!s->t->is_client && s->trailing_md_recvd && s->recv_trailing_md_op) {
+      INPROC_LOG(GPR_DEBUG,
+                 "cancel_stream %p scheduling trailing-md-on-complete %p", s,
+                 s->cancel_self_error);
+      GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete,
+                         GRPC_ERROR_REF(s->cancel_self_error));
+      s->recv_trailing_md_op = NULL;
+    }
+  }
+
+  close_other_side_locked(exec_ctx, s, "cancel_stream:other_side");
+  close_stream_locked(exec_ctx, s);
+
+  GRPC_ERROR_UNREF(error);
+  return ret;
+}
+
+static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                              grpc_stream *gs,
+                              grpc_transport_stream_op_batch *op) {
+  INPROC_LOG(GPR_DEBUG, "perform_stream_op %p %p %p", gt, gs, op);
+  inproc_stream *s = (inproc_stream *)gs;
+  gpr_mu *mu = &s->t->mu->mu;  // save aside in case s gets closed
+  gpr_mu_lock(mu);
+
+  if (GRPC_TRACER_ON(grpc_inproc_trace)) {
+    if (op->send_initial_metadata) {
+      log_metadata(op->payload->send_initial_metadata.send_initial_metadata,
+                   s->t->is_client, true);
+    }
+    if (op->send_trailing_metadata) {
+      log_metadata(op->payload->send_trailing_metadata.send_trailing_metadata,
+                   s->t->is_client, false);
+    }
+  }
+  grpc_error *error = GRPC_ERROR_NONE;
+  grpc_closure *on_complete = op->on_complete;
+  if (on_complete == NULL) {
+    on_complete = &do_nothing_closure;
+  }
+
+  if (op->cancel_stream) {
+    // Call cancel_stream_locked without ref'ing the cancel_error because
+    // this function is responsible to make sure that that field gets unref'ed
+    cancel_stream_locked(exec_ctx, s, op->payload->cancel_stream.cancel_error);
+    // this op can complete without an error
+  } else if (s->cancel_self_error != GRPC_ERROR_NONE) {
+    // already self-canceled so still give it an error
+    error = GRPC_ERROR_REF(s->cancel_self_error);
+  } else {
+    INPROC_LOG(GPR_DEBUG, "perform_stream_op %p%s%s%s%s%s%s", s,
+               op->send_initial_metadata ? " send_initial_metadata" : "",
+               op->send_message ? " send_message" : "",
+               op->send_trailing_metadata ? " send_trailing_metadata" : "",
+               op->recv_initial_metadata ? " recv_initial_metadata" : "",
+               op->recv_message ? " recv_message" : "",
+               op->recv_trailing_metadata ? " recv_trailing_metadata" : "");
+  }
+
+  bool needs_close = false;
+
+  if (error == GRPC_ERROR_NONE &&
+      (op->send_initial_metadata || op->send_message ||
+       op->send_trailing_metadata)) {
+    inproc_stream *other = s->other_side;
+    if (s->t->is_closed) {
+      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Endpoint already shutdown");
+    }
+    if (error == GRPC_ERROR_NONE && op->send_initial_metadata) {
+      grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_initial_md
+                                                  : &other->to_read_initial_md;
+      uint32_t *destflags = (other == NULL) ? &s->write_buffer_initial_md_flags
+                                            : &other->to_read_initial_md_flags;
+      bool *destfilled = (other == NULL) ? &s->write_buffer_initial_md_filled
+                                         : &other->to_read_initial_md_filled;
+      if (*destfilled || s->initial_md_sent) {
+        // The buffer is already in use; that's an error!
+        INPROC_LOG(GPR_DEBUG, "Extra initial metadata %p", s);
+        error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra initial metadata");
+      } else {
+        if (!other->closed) {
+          fill_in_metadata(
+              exec_ctx, s,
+              op->payload->send_initial_metadata.send_initial_metadata,
+              op->payload->send_initial_metadata.send_initial_metadata_flags,
+              dest, destflags, destfilled);
+        }
+        if (s->t->is_client) {
+          gpr_timespec *dl =
+              (other == NULL) ? &s->write_buffer_deadline : &other->deadline;
+          *dl = gpr_time_min(*dl, op->payload->send_initial_metadata
+                                      .send_initial_metadata->deadline);
+          s->initial_md_sent = true;
+        }
+      }
+    }
+    if (error == GRPC_ERROR_NONE && op->send_message) {
+      size_t remaining = op->payload->send_message.send_message->length;
+      grpc_slice_buffer *dest = slice_buffer_list_append(
+          (other == NULL) ? &s->write_buffer_message : &other->to_read_message);
+      do {
+        grpc_slice message_slice;
+        grpc_closure unused;
+        GPR_ASSERT(grpc_byte_stream_next(exec_ctx,
+                                         op->payload->send_message.send_message,
+                                         SIZE_MAX, &unused));
+        grpc_byte_stream_pull(exec_ctx, op->payload->send_message.send_message,
+                              &message_slice);
+        remaining -= GRPC_SLICE_LENGTH(message_slice);
+        grpc_slice_buffer_add(dest, message_slice);
+      } while (remaining != 0);
+    }
+    if (error == GRPC_ERROR_NONE && op->send_trailing_metadata) {
+      grpc_metadata_batch *dest = (other == NULL) ? &s->write_buffer_trailing_md
+                                                  : &other->to_read_trailing_md;
+      bool *destfilled = (other == NULL) ? &s->write_buffer_trailing_md_filled
+                                         : &other->to_read_trailing_md_filled;
+      if (*destfilled || s->trailing_md_sent) {
+        // The buffer is already in use; that's an error!
+        INPROC_LOG(GPR_DEBUG, "Extra trailing metadata %p", s);
+        error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Extra trailing metadata");
+      } else {
+        if (!other->closed) {
+          fill_in_metadata(
+              exec_ctx, s,
+              op->payload->send_trailing_metadata.send_trailing_metadata, 0,
+              dest, NULL, destfilled);
+        }
+        s->trailing_md_sent = true;
+        if (!s->t->is_client && s->trailing_md_recvd &&
+            s->recv_trailing_md_op) {
+          INPROC_LOG(GPR_DEBUG,
+                     "perform_stream_op %p scheduling trailing-md-on-complete",
+                     s);
+          GRPC_CLOSURE_SCHED(exec_ctx, s->recv_trailing_md_op->on_complete,
+                             GRPC_ERROR_NONE);
+          s->recv_trailing_md_op = NULL;
+          needs_close = true;
+        }
+      }
+    }
+    if (other != NULL && other->reads_needed) {
+      if (!other->read_closure_scheduled) {
+        GRPC_CLOSURE_SCHED(exec_ctx, &other->read_closure, error);
+        other->read_closure_scheduled = true;
+      }
+      other->reads_needed = false;
+    }
+  }
+  if (error == GRPC_ERROR_NONE &&
+      (op->recv_initial_metadata || op->recv_message ||
+       op->recv_trailing_metadata)) {
+    // If there are any reads, mark it so that the read closure will react to
+    // them
+    if (op->recv_initial_metadata) {
+      s->recv_initial_md_op = op;
+    }
+    if (op->recv_message) {
+      s->recv_message_op = op;
+    }
+    if (op->recv_trailing_metadata) {
+      s->recv_trailing_md_op = op;
+    }
+
+    // We want to initiate the closure if:
+    // 1. There is initial metadata and something ready to take that
+    // 2. There is a message and something ready to take it
+    // 3. There is trailing metadata, even if nothing specifically wants
+    //    that because that can shut down the message as well
+    if ((s->to_read_initial_md_filled && op->recv_initial_metadata) ||
+        ((!slice_buffer_list_empty(&s->to_read_message) ||
+          s->trailing_md_recvd) &&
+         op->recv_message) ||
+        (s->to_read_trailing_md_filled)) {
+      if (!s->read_closure_scheduled) {
+        GRPC_CLOSURE_SCHED(exec_ctx, &s->read_closure, GRPC_ERROR_NONE);
+        s->read_closure_scheduled = true;
+      }
+    } else {
+      s->reads_needed = true;
+    }
+  } else {
+    if (error != GRPC_ERROR_NONE) {
+      // Schedule op's read closures that we didn't push to read state machine
+      if (op->recv_initial_metadata) {
+        INPROC_LOG(
+            GPR_DEBUG,
+            "perform_stream_op error %p scheduling initial-metadata-ready %p",
+            s, error);
+        GRPC_CLOSURE_SCHED(
+            exec_ctx,
+            op->payload->recv_initial_metadata.recv_initial_metadata_ready,
+            GRPC_ERROR_REF(error));
+      }
+      if (op->recv_message) {
+        INPROC_LOG(
+            GPR_DEBUG,
+            "perform_stream_op error %p scheduling recv message-ready %p", s,
+            error);
+        GRPC_CLOSURE_SCHED(exec_ctx,
+                           op->payload->recv_message.recv_message_ready,
+                           GRPC_ERROR_REF(error));
+      }
+    }
+    INPROC_LOG(GPR_DEBUG, "perform_stream_op %p scheduling on_complete %p", s,
+               error);
+    GRPC_CLOSURE_SCHED(exec_ctx, on_complete, GRPC_ERROR_REF(error));
+  }
+  if (needs_close) {
+    close_other_side_locked(exec_ctx, s, "perform_stream_op:other_side");
+    close_stream_locked(exec_ctx, s);
+  }
+  gpr_mu_unlock(mu);
+  GRPC_ERROR_UNREF(error);
+}
+
+static void close_transport_locked(grpc_exec_ctx *exec_ctx,
+                                   inproc_transport *t) {
+  INPROC_LOG(GPR_DEBUG, "close_transport %p %d", t, t->is_closed);
+  grpc_connectivity_state_set(
+      exec_ctx, &t->connectivity, GRPC_CHANNEL_SHUTDOWN,
+      GRPC_ERROR_CREATE_FROM_STATIC_STRING("Closing transport."),
+      "close transport");
+  if (!t->is_closed) {
+    t->is_closed = true;
+    /* Also end all streams on this transport */
+    while (t->stream_list != NULL) {
+      // cancel_stream_locked also adjusts stream list
+      cancel_stream_locked(
+          exec_ctx, t->stream_list,
+          grpc_error_set_int(
+              GRPC_ERROR_CREATE_FROM_STATIC_STRING("Transport closed"),
+              GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
+    }
+  }
+}
+
+static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                                 grpc_transport_op *op) {
+  inproc_transport *t = (inproc_transport *)gt;
+  INPROC_LOG(GPR_DEBUG, "perform_transport_op %p %p", t, op);
+  gpr_mu_lock(&t->mu->mu);
+  if (op->on_connectivity_state_change) {
+    grpc_connectivity_state_notify_on_state_change(
+        exec_ctx, &t->connectivity, op->connectivity_state,
+        op->on_connectivity_state_change);
+  }
+  if (op->set_accept_stream) {
+    t->accept_stream_cb = op->set_accept_stream_fn;
+    t->accept_stream_data = op->set_accept_stream_user_data;
+  }
+  if (op->on_consumed) {
+    GRPC_CLOSURE_SCHED(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
+  }
+
+  bool do_close = false;
+  if (op->goaway_error != GRPC_ERROR_NONE) {
+    do_close = true;
+    GRPC_ERROR_UNREF(op->goaway_error);
+  }
+  if (op->disconnect_with_error != GRPC_ERROR_NONE) {
+    do_close = true;
+    GRPC_ERROR_UNREF(op->disconnect_with_error);
+  }
+
+  if (do_close) {
+    close_transport_locked(exec_ctx, t);
+  }
+  gpr_mu_unlock(&t->mu->mu);
+}
+
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                           grpc_stream *gs,
+                           grpc_closure *then_schedule_closure) {
+  INPROC_LOG(GPR_DEBUG, "destroy_stream %p %p", gs, then_schedule_closure);
+  inproc_stream *s = (inproc_stream *)gs;
+  s->closure_at_destroy = then_schedule_closure;
+  really_destroy_stream(exec_ctx, s);
+}
+
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+  inproc_transport *t = (inproc_transport *)gt;
+  INPROC_LOG(GPR_DEBUG, "destroy_transport %p", t);
+  gpr_mu_lock(&t->mu->mu);
+  close_transport_locked(exec_ctx, t);
+  gpr_mu_unlock(&t->mu->mu);
+  unref_transport(exec_ctx, t->other_side);
+  unref_transport(exec_ctx, t);
+}
+
+/*******************************************************************************
+ * Main inproc transport functions
+ */
+static void inproc_transports_create(grpc_exec_ctx *exec_ctx,
+                                     grpc_transport **server_transport,
+                                     const grpc_channel_args *server_args,
+                                     grpc_transport **client_transport,
+                                     const grpc_channel_args *client_args) {
+  INPROC_LOG(GPR_DEBUG, "inproc_transports_create");
+  inproc_transport *st = gpr_zalloc(sizeof(*st));
+  inproc_transport *ct = gpr_zalloc(sizeof(*ct));
+  // Share one lock between both sides since both sides get affected
+  st->mu = ct->mu = gpr_malloc(sizeof(*st->mu));
+  gpr_mu_init(&st->mu->mu);
+  gpr_ref_init(&st->mu->refs, 2);
+  st->base.vtable = &inproc_vtable;
+  ct->base.vtable = &inproc_vtable;
+  // Start each side of transport with 2 refs since they each have a ref
+  // to the other
+  gpr_ref_init(&st->refs, 2);
+  gpr_ref_init(&ct->refs, 2);
+  st->is_client = false;
+  ct->is_client = true;
+  grpc_connectivity_state_init(&st->connectivity, GRPC_CHANNEL_READY,
+                               "inproc_server");
+  grpc_connectivity_state_init(&ct->connectivity, GRPC_CHANNEL_READY,
+                               "inproc_client");
+  st->other_side = ct;
+  ct->other_side = st;
+  st->stream_list = NULL;
+  ct->stream_list = NULL;
+  *server_transport = (grpc_transport *)st;
+  *client_transport = (grpc_transport *)ct;
+}
+
+grpc_channel *grpc_inproc_channel_create(grpc_server *server,
+                                         grpc_channel_args *args,
+                                         void *reserved) {
+  GRPC_API_TRACE("grpc_inproc_channel_create(server=%p, args=%p)", 2,
+                 (server, args));
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
+  const grpc_channel_args *server_args = grpc_server_get_channel_args(server);
+
+  // Add a default authority channel argument for the client
+
+  grpc_arg default_authority_arg;
+  default_authority_arg.type = GRPC_ARG_STRING;
+  default_authority_arg.key = GRPC_ARG_DEFAULT_AUTHORITY;
+  default_authority_arg.value.string = "inproc.authority";
+  grpc_channel_args *client_args =
+      grpc_channel_args_copy_and_add(args, &default_authority_arg, 1);
+
+  grpc_transport *server_transport;
+  grpc_transport *client_transport;
+  inproc_transports_create(&exec_ctx, &server_transport, server_args,
+                           &client_transport, client_args);
+
+  grpc_server_setup_transport(&exec_ctx, server, server_transport, NULL,
+                              server_args);
+  grpc_channel *channel =
+      grpc_channel_create(&exec_ctx, "inproc", client_args,
+                          GRPC_CLIENT_DIRECT_CHANNEL, client_transport);
+
+  // Free up created channel args
+  grpc_channel_args_destroy(&exec_ctx, client_args);
+
+  // Now finish scheduled operations
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  return channel;
+}
+
+/*******************************************************************************
+ * INTEGRATION GLUE
+ */
+
+static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                        grpc_stream *gs, grpc_pollset *pollset) {
+  // Nothing to do here
+}
+
+static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                            grpc_stream *gs, grpc_pollset_set *pollset_set) {
+  // Nothing to do here
+}
+
+static char *get_peer(grpc_exec_ctx *exec_ctx, grpc_transport *t) {
+  return gpr_strdup("inproc");
+}
+
+static grpc_endpoint *get_endpoint(grpc_exec_ctx *exec_ctx, grpc_transport *t) {
+  return NULL;
+}
+
+static const grpc_transport_vtable inproc_vtable = {
+    sizeof(inproc_stream), "inproc",
+    init_stream,           set_pollset,
+    set_pollset_set,       perform_stream_op,
+    perform_transport_op,  destroy_stream,
+    destroy_transport,     get_peer,
+    get_endpoint};
+
+/*******************************************************************************
+ * GLOBAL INIT AND DESTROY
+ */
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
+
+void grpc_inproc_transport_init(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GRPC_CLOSURE_INIT(&do_nothing_closure, do_nothing, NULL,
+                    grpc_schedule_on_exec_ctx);
+  g_empty_slice = grpc_slice_from_static_buffer(NULL, 0);
+
+  grpc_slice key_tmp = grpc_slice_from_static_string(":path");
+  g_fake_path_key = grpc_slice_intern(key_tmp);
+  grpc_slice_unref_internal(&exec_ctx, key_tmp);
+
+  g_fake_path_value = grpc_slice_from_static_string("/");
+
+  grpc_slice auth_tmp = grpc_slice_from_static_string(":authority");
+  g_fake_auth_key = grpc_slice_intern(auth_tmp);
+  grpc_slice_unref_internal(&exec_ctx, auth_tmp);
+
+  g_fake_auth_value = grpc_slice_from_static_string("inproc-fail");
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+void grpc_inproc_transport_shutdown(void) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_slice_unref_internal(&exec_ctx, g_empty_slice);
+  grpc_slice_unref_internal(&exec_ctx, g_fake_path_key);
+  grpc_slice_unref_internal(&exec_ctx, g_fake_path_value);
+  grpc_slice_unref_internal(&exec_ctx, g_fake_auth_key);
+  grpc_slice_unref_internal(&exec_ctx, g_fake_auth_value);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
diff --git a/src/core/ext/transport/inproc/inproc_transport.h b/src/core/ext/transport/inproc/inproc_transport.h
new file mode 100644
index 0000000..37e6d99
--- /dev/null
+++ b/src/core/ext/transport/inproc/inproc_transport.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H
+#define GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H
+
+#include "src/core/lib/transport/transport_impl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+grpc_channel *grpc_inproc_channel_create(grpc_server *server,
+                                         grpc_channel_args *args,
+                                         void *reserved);
+
+extern grpc_tracer_flag grpc_inproc_trace;
+
+void grpc_inproc_transport_init(void);
+void grpc_inproc_transport_shutdown(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H */
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index a5ae04c..cff77e6 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -121,6 +121,10 @@
   g_event_engine = ev_engine;
 }
 
+const grpc_event_engine_vtable *grpc_get_event_engine_test_only() {
+  return g_event_engine;
+}
+
 /* Call this only after calling grpc_event_engine_init() */
 const char *grpc_get_poll_strategy_name() { return g_poll_strategy_name; }
 
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 54c4f2e..0de7333 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -153,7 +153,9 @@
 typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
 extern grpc_poll_function_type grpc_poll_function;
 
-/* This should be used for testing purposes ONLY */
+/* WARNING: The following two functions should be used for testing purposes
+ * ONLY */
 void grpc_set_event_engine_test_only(const grpc_event_engine_vtable *);
+const grpc_event_engine_vtable *grpc_get_event_engine_test_only();
 
 #endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c
index 589a6f9..4357657 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.c
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c
@@ -125,6 +125,13 @@
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &jwt_vtable;
   c->key = key;
+  gpr_timespec max_token_lifetime = grpc_max_auth_token_lifetime();
+  if (gpr_time_cmp(token_lifetime, max_token_lifetime) > 0) {
+    gpr_log(GPR_INFO,
+            "Cropping token lifetime to maximum allowed value (%d secs).",
+            (int)max_token_lifetime.tv_sec);
+    token_lifetime = grpc_max_auth_token_lifetime();
+  }
   c->jwt_lifetime = token_lifetime;
   gpr_mu_init(&c->cache_mu);
   jwt_reset_cache(exec_ctx, c);
diff --git a/src/core/plugin_registry/grpc_plugin_registry.c b/src/core/plugin_registry/grpc_plugin_registry.c
index a816186..b0d06a3 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_plugin_registry.c
@@ -26,6 +26,8 @@
 extern void grpc_deadline_filter_shutdown(void);
 extern void grpc_client_channel_init(void);
 extern void grpc_client_channel_shutdown(void);
+extern void grpc_inproc_plugin_init(void);
+extern void grpc_inproc_plugin_shutdown(void);
 extern void grpc_resolver_fake_init(void);
 extern void grpc_resolver_fake_shutdown(void);
 extern void grpc_lb_policy_grpclb_init(void);
@@ -60,6 +62,8 @@
                        grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
+  grpc_register_plugin(grpc_inproc_plugin_init,
+                       grpc_inproc_plugin_shutdown);
   grpc_register_plugin(grpc_resolver_fake_init,
                        grpc_resolver_fake_shutdown);
   grpc_register_plugin(grpc_lb_policy_grpclb_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
index 809d444..7eb599d 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.c
@@ -26,6 +26,8 @@
 extern void grpc_deadline_filter_shutdown(void);
 extern void grpc_client_channel_init(void);
 extern void grpc_client_channel_shutdown(void);
+extern void grpc_inproc_plugin_init(void);
+extern void grpc_inproc_plugin_shutdown(void);
 extern void grpc_resolver_dns_ares_init(void);
 extern void grpc_resolver_dns_ares_shutdown(void);
 extern void grpc_resolver_dns_native_init(void);
@@ -60,6 +62,8 @@
                        grpc_deadline_filter_shutdown);
   grpc_register_plugin(grpc_client_channel_init,
                        grpc_client_channel_shutdown);
+  grpc_register_plugin(grpc_inproc_plugin_init,
+                       grpc_inproc_plugin_shutdown);
   grpc_register_plugin(grpc_resolver_dns_ares_init,
                        grpc_resolver_dns_ares_shutdown);
   grpc_register_plugin(grpc_resolver_dns_native_init,
diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc
index 3bff999..60e067d 100644
--- a/src/cpp/server/server_cc.cc
+++ b/src/cpp/server/server_cc.cc
@@ -36,7 +36,9 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
+#include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/profiling/timers.h"
+#include "src/cpp/client/create_channel_internal.h"
 #include "src/cpp/server/health/default_health_check_service.h"
 #include "src/cpp/thread_manager/thread_manager.h"
 
@@ -422,6 +424,13 @@
 
 grpc_server* Server::c_server() { return server_; }
 
+std::shared_ptr<Channel> Server::InProcessChannel(
+    const ChannelArguments& args) {
+  grpc_channel_args channel_args = args.c_channel_args();
+  return CreateChannelInternal(
+      "inproc", grpc_inproc_channel_create(server_, &channel_args, nullptr));
+}
+
 static grpc_server_register_method_payload_handling PayloadHandlingForMethod(
     internal::RpcServiceMethod* method) {
   switch (method->method_type()) {
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index ea5bdba..b30d340 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -270,6 +270,8 @@
   'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
   'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
   'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+  'src/core/ext/transport/inproc/inproc_plugin.c',
+  'src/core/ext/transport/inproc/inproc_transport.c',
   'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c',
   'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
   'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
diff --git a/test/core/end2end/fixtures/inproc.c b/test/core/end2end/fixtures/inproc.c
new file mode 100644
index 0000000..6f742f0
--- /dev/null
+++ b/test/core/end2end/fixtures/inproc.c
@@ -0,0 +1,96 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+#include "src/core/ext/filters/client_channel/client_channel.h"
+#include "src/core/ext/filters/http/server/http_server_filter.h"
+#include "src/core/ext/transport/inproc/inproc_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"
+
+typedef struct inproc_fixture_data {
+  bool dummy;  // reserved for future expansion. Struct can't be empty
+} inproc_fixture_data;
+
+static grpc_end2end_test_fixture inproc_create_fixture(
+    grpc_channel_args *client_args, grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  inproc_fixture_data *ffd = gpr_malloc(sizeof(inproc_fixture_data));
+  memset(&f, 0, sizeof(f));
+
+  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 inproc_init_client(grpc_end2end_test_fixture *f,
+                        grpc_channel_args *client_args) {
+  f->client = grpc_inproc_channel_create(f->server, client_args, NULL);
+  GPR_ASSERT(f->client);
+}
+
+void inproc_init_server(grpc_end2end_test_fixture *f,
+                        grpc_channel_args *server_args) {
+  if (f->server) {
+    grpc_server_destroy(f->server);
+  }
+  f->server = grpc_server_create(server_args, NULL);
+  grpc_server_register_completion_queue(f->server, f->cq, NULL);
+  grpc_server_start(f->server);
+}
+
+void inproc_tear_down(grpc_end2end_test_fixture *f) {
+  inproc_fixture_data *ffd = f->fixture_data;
+  gpr_free(ffd);
+}
+
+/* All test configurations */
+static grpc_end2end_test_config configs[] = {
+    {"inproc", FEATURE_MASK_SUPPORTS_AUTHORITY_HEADER, inproc_create_fixture,
+     inproc_init_client, inproc_init_server, inproc_tear_down},
+};
+
+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/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index 6dffacf..6878964 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -24,15 +24,15 @@
 
 FixtureOptions = collections.namedtuple(
     'FixtureOptions',
-    'fullstack includes_proxy dns_resolver secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression')
+    'fullstack includes_proxy dns_resolver name_resolution secure platforms ci_mac tracing exclude_configs exclude_iomgrs large_writes enables_compression supports_compression is_inproc is_http2')
 default_unsecure_fixture_options = FixtureOptions(
-    True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True, False)
+    True, False, True, True, False, ['windows', 'linux', 'mac', 'posix'], True, False, [], [], True, False, True, False, True)
 socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
 default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
 uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
 fd_unsecure_fixture_options = default_unsecure_fixture_options._replace(
     dns_resolver=False, fullstack=False, platforms=['linux', 'mac', 'posix'], exclude_iomgrs=['uv'])
-
+inproc_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, fullstack=False, name_resolution=False, supports_compression=False, is_inproc=True, is_http2=False)
 
 # maps fixture name to whether it requires the security library
 END2END_FIXTURES = {
@@ -64,12 +64,13 @@
     'h2_ssl_proxy': default_secure_fixture_options._replace(
         includes_proxy=True, ci_mac=False, exclude_iomgrs=['uv']),
     'h2_uds': uds_fixture_options,
+    'inproc': inproc_fixture_options
 }
 
 TestOptions = collections.namedtuple(
     'TestOptions',
-    'needs_fullstack needs_dns proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allow_compression')
-default_test_options = TestOptions(False, False, True, False, True, 1.0, [], False, False, True)
+    'needs_fullstack needs_dns needs_names proxyable secure traceable cpu_cost exclude_iomgrs large_writes flaky allows_compression needs_compression exclude_inproc needs_http2')
+default_test_options = TestOptions(False, False, False, True, False, True, 1.0, [], False, False, True, False, False, False)
 connectivity_test_options = default_test_options._replace(needs_fullstack=True)
 
 LOWCPU = 0.1
@@ -77,12 +78,12 @@
 # maps test names to options
 END2END_TESTS = {
     'authority_not_supported': default_test_options,
-    'bad_hostname': default_test_options,
+    'bad_hostname': default_test_options._replace(needs_names=True),
     'bad_ping': connectivity_test_options._replace(proxyable=False),
     'binary_metadata': default_test_options._replace(cpu_cost=LOWCPU),
     'resource_quota_server': default_test_options._replace(large_writes=True,
                                                            proxyable=False,
-                                                           allow_compression=False),
+                                                           allows_compression=False),
     'call_creds': default_test_options._replace(secure=True),
     'cancel_after_accept': default_test_options._replace(cpu_cost=LOWCPU),
     'cancel_after_client_done': default_test_options._replace(cpu_cost=LOWCPU),
@@ -91,17 +92,17 @@
     'cancel_before_invoke': default_test_options._replace(cpu_cost=LOWCPU),
     'cancel_in_a_vacuum': default_test_options._replace(cpu_cost=LOWCPU),
     'cancel_with_status': default_test_options._replace(cpu_cost=LOWCPU),
-    'compressed_payload': default_test_options._replace(proxyable=False),
-    'connectivity': connectivity_test_options._replace(
+    'compressed_payload': default_test_options._replace(proxyable=False,needs_compression=True),
+    'connectivity': connectivity_test_options._replace(needs_names=True,
         proxyable=False, cpu_cost=LOWCPU, exclude_iomgrs=['uv']),
     'default_host': default_test_options._replace(needs_fullstack=True,
-                                                  needs_dns=True),
-    'disappearing_server': connectivity_test_options._replace(flaky=True),
+                                                  needs_dns=True,needs_names=True),
+    'disappearing_server': connectivity_test_options._replace(flaky=True,needs_names=True),
     'empty_batch': default_test_options._replace(cpu_cost=LOWCPU),
     'filter_causes_close': default_test_options._replace(cpu_cost=LOWCPU),
     'filter_call_init_fails': default_test_options,
     'filter_latency': default_test_options._replace(cpu_cost=LOWCPU),
-    'graceful_server_shutdown': default_test_options._replace(cpu_cost=LOWCPU),
+    'graceful_server_shutdown': default_test_options._replace(cpu_cost=LOWCPU,exclude_inproc=True),
     'hpack_size': default_test_options._replace(proxyable=False,
                                                 traceable=False,
                                                 cpu_cost=LOWCPU),
@@ -109,11 +110,13 @@
     'idempotent_request': default_test_options,
     'invoke_large_request': default_test_options,
     'keepalive_timeout': default_test_options._replace(proxyable=False,
-                                                       cpu_cost=LOWCPU),
+                                                       cpu_cost=LOWCPU,
+                                                       needs_http2=True),
     'large_metadata': default_test_options,
     'max_concurrent_streams': default_test_options._replace(
-        proxyable=False, cpu_cost=LOWCPU),
-    'max_connection_age': default_test_options._replace(cpu_cost=LOWCPU),
+        proxyable=False, cpu_cost=LOWCPU, exclude_inproc=True),
+    'max_connection_age': default_test_options._replace(cpu_cost=LOWCPU,
+                                                        exclude_inproc=True),
     'max_connection_idle': connectivity_test_options._replace(
         proxyable=False, exclude_iomgrs=['uv'], cpu_cost=LOWCPU),
     'max_message_length': default_test_options._replace(cpu_cost=LOWCPU),
@@ -151,6 +154,9 @@
   if END2END_TESTS[t].needs_dns:
     if not END2END_FIXTURES[f].dns_resolver:
       return False
+  if END2END_TESTS[t].needs_names:
+    if not END2END_FIXTURES[f].name_resolution:
+      return False
   if not END2END_TESTS[t].proxyable:
     if END2END_FIXTURES[f].includes_proxy:
       return False
@@ -160,9 +166,18 @@
   if END2END_TESTS[t].large_writes:
     if not END2END_FIXTURES[f].large_writes:
       return False
-  if not END2END_TESTS[t].allow_compression:
+  if not END2END_TESTS[t].allows_compression:
     if END2END_FIXTURES[f].enables_compression:
       return False
+  if END2END_TESTS[t].needs_compression:
+    if not END2END_FIXTURES[f].supports_compression:
+      return False
+  if END2END_TESTS[t].exclude_inproc:
+    if END2END_FIXTURES[f].is_inproc:
+      return False
+  if END2END_TESTS[t].needs_http2:
+    if not END2END_FIXTURES[f].is_http2:
+      return False
   return True
 
 
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 3312f4e..ea9ad03 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -19,14 +19,18 @@
 
 
 def fixture_options(fullstack=True, includes_proxy=False, dns_resolver=True,
-                    secure=True, tracing=False,
-                    platforms=['windows', 'linux', 'mac', 'posix']):
+                    name_resolution=True, secure=True, tracing=False,
+                    platforms=['windows', 'linux', 'mac', 'posix'],
+                    is_inproc=False, is_http2=True):
   return struct(
     fullstack=fullstack,
     includes_proxy=includes_proxy,
     dns_resolver=dns_resolver,
+    name_resolution=name_resolution,
     secure=secure,
     tracing=tracing,
+    is_inproc=is_inproc,
+    is_http2=is_http2
     #platforms=platforms
   )
 
@@ -55,24 +59,31 @@
     'h2_ssl_proxy': fixture_options(includes_proxy=True, secure=True),
     'h2_uds': fixture_options(dns_resolver=False,
                               platforms=['linux', 'mac', 'posix']),
+    'inproc': fixture_options(fullstack=False, dns_resolver=False,
+                              name_resolution=False, is_inproc=True,
+                              is_http2=False),
 }
 
 
-def test_options(needs_fullstack=False, needs_dns=False, proxyable=True,
-                 secure=False, traceable=False):
+def test_options(needs_fullstack=False, needs_dns=False, needs_names=False,
+                 proxyable=True, secure=False, traceable=False,
+                 exclude_inproc=False, needs_http2=False):
   return struct(
     needs_fullstack=needs_fullstack,
     needs_dns=needs_dns,
+    needs_names=needs_names,
     proxyable=proxyable,
     secure=secure,
-    traceable=traceable
+    traceable=traceable,
+    exclude_inproc=exclude_inproc,
+    needs_http2=needs_http2
   )
 
 
 # maps test names to options
 END2END_TESTS = {
-    'bad_hostname': test_options(),
-    'bad_ping': test_options(),
+    'bad_hostname': test_options(needs_names=True),
+    'bad_ping': test_options(needs_fullstack=True,proxyable=False),
     'binary_metadata': test_options(),
     'resource_quota_server': test_options(proxyable=False),
     'call_creds': test_options(secure=True),
@@ -83,22 +94,25 @@
     'cancel_before_invoke': test_options(),
     'cancel_in_a_vacuum': test_options(),
     'cancel_with_status': test_options(),
-    'compressed_payload': test_options(proxyable=False),
-    'connectivity': test_options(needs_fullstack=True, proxyable=False),
-    'default_host': test_options(needs_fullstack=True, needs_dns=True),
-    'disappearing_server': test_options(needs_fullstack=True),
+    'compressed_payload': test_options(proxyable=False, exclude_inproc=True),
+    'connectivity': test_options(needs_fullstack=True, needs_names=True,
+                                 proxyable=False),
+    'default_host': test_options(needs_fullstack=True, needs_dns=True,
+                                 needs_names=True),
+    'disappearing_server': test_options(needs_fullstack=True,needs_names=True),
     'empty_batch': test_options(),
     'filter_causes_close': test_options(),
     'filter_call_init_fails': test_options(),
-    'graceful_server_shutdown': test_options(),
-    'hpack_size': test_options(proxyable=False, traceable=False),
+    'graceful_server_shutdown': test_options(exclude_inproc=True),
+    'hpack_size': test_options(proxyable=False, traceable=False,
+                               exclude_inproc=True),
     'high_initial_seqno': test_options(),
     'idempotent_request': test_options(),
     'invoke_large_request': test_options(),
-    'keepalive_timeout': test_options(proxyable=False),
+    'keepalive_timeout': test_options(proxyable=False, needs_http2=True),
     'large_metadata': test_options(),
-    'max_concurrent_streams': test_options(proxyable=False),
-    'max_connection_age': test_options(),
+    'max_concurrent_streams': test_options(proxyable=False, exclude_inproc=True),
+    'max_connection_age': test_options(exclude_inproc=True),
     'max_connection_idle': test_options(needs_fullstack=True, proxyable=False),
     'max_message_length': test_options(),
     'negative_deadline': test_options(),
@@ -136,12 +150,21 @@
   if topt.needs_dns:
     if not fopt.dns_resolver:
       return False
+  if topt.needs_names:
+    if not fopt.name_resolution:
+      return False
   if not topt.proxyable:
     if fopt.includes_proxy:
       return False
   if not topt.traceable:
     if fopt.tracing:
       return False
+  if topt.exclude_inproc:
+    if fopt.is_inproc:
+      return False
+  if topt.needs_http2:
+    if not fopt.is_http2:
+      return False
   return True
 
 
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 9d419c7..a76cb04 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -816,6 +816,45 @@
   GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0);
 }
 
+static grpc_service_account_jwt_access_credentials *creds_as_jwt(
+    grpc_call_credentials *creds) {
+  GPR_ASSERT(creds != NULL);
+  GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_JWT) == 0);
+  return (grpc_service_account_jwt_access_credentials *)creds;
+}
+
+static void test_jwt_creds_lifetime(void) {
+  char *json_key_string = test_json_key_str();
+
+  // Max lifetime.
+  grpc_call_credentials *jwt_creds =
+      grpc_service_account_jwt_access_credentials_create(
+          json_key_string, grpc_max_auth_token_lifetime(), NULL);
+  GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime,
+                          grpc_max_auth_token_lifetime()) == 0);
+  grpc_call_credentials_release(jwt_creds);
+
+  // Shorter lifetime.
+  gpr_timespec token_lifetime = {10, 0, GPR_TIMESPAN};
+  GPR_ASSERT(gpr_time_cmp(grpc_max_auth_token_lifetime(), token_lifetime) > 0);
+  jwt_creds = grpc_service_account_jwt_access_credentials_create(
+      json_key_string, token_lifetime, NULL);
+  GPR_ASSERT(
+      gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime, token_lifetime) == 0);
+  grpc_call_credentials_release(jwt_creds);
+
+  // Cropped lifetime.
+  gpr_timespec add_to_max = {10, 0, GPR_TIMESPAN};
+  token_lifetime = gpr_time_add(grpc_max_auth_token_lifetime(), add_to_max);
+  jwt_creds = grpc_service_account_jwt_access_credentials_create(
+      json_key_string, token_lifetime, NULL);
+  GPR_ASSERT(gpr_time_cmp(creds_as_jwt(jwt_creds)->jwt_lifetime,
+                          grpc_max_auth_token_lifetime()) == 0);
+  grpc_call_credentials_release(jwt_creds);
+
+  gpr_free(json_key_string);
+}
+
 static void test_jwt_creds_success(void) {
   char *json_key_string = test_json_key_str();
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -1216,6 +1255,7 @@
   test_compute_engine_creds_failure();
   test_refresh_token_creds_success();
   test_refresh_token_creds_failure();
+  test_jwt_creds_lifetime();
   test_jwt_creds_success();
   test_jwt_creds_signing_failure();
   test_google_default_creds_auth_key();
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index 7b78071..7cb7b26 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -212,14 +212,16 @@
 
 class TestScenario {
  public:
-  TestScenario(bool non_block, const grpc::string& creds_type, bool hcs,
-               const grpc::string& content)
+  TestScenario(bool non_block, bool inproc_stub, const grpc::string& creds_type,
+               bool hcs, const grpc::string& content)
       : disable_blocking(non_block),
+        inproc(inproc_stub),
         health_check_service(hcs),
         credentials_type(creds_type),
         message_content(content) {}
   void Log() const;
   bool disable_blocking;
+  bool inproc;
   bool health_check_service;
   // Although the below grpc::string's are logically const, we can't declare
   // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
@@ -232,6 +234,7 @@
                                 const TestScenario& scenario) {
   return out << "TestScenario{disable_blocking="
              << (scenario.disable_blocking ? "true" : "false")
+             << ", inproc=" << (scenario.inproc ? "true" : "false")
              << ", credentials='" << scenario.credentials_type
              << ", health_check_service="
              << (scenario.health_check_service ? "true" : "false")
@@ -294,7 +297,9 @@
     auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
         GetParam().credentials_type, &args);
     std::shared_ptr<Channel> channel =
-        CreateCustomChannel(server_address_.str(), channel_creds, args);
+        !(GetParam().inproc)
+            ? CreateCustomChannel(server_address_.str(), channel_creds, args)
+            : server_->InProcessChannel(args);
     stub_ = grpc::testing::EchoTestService::NewStub(channel);
   }
 
@@ -512,7 +517,7 @@
   // up until server read is initiated. For write of send_request smaller than
   // the flow control window size, the request can take the free ride with
   // initial metadata due to coalescing, thus write tag:3 will come up here.
-  if (GetParam().message_content.length() < 65536) {
+  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
     Verifier(GetParam().disable_blocking)
         .Expect(2, true)
         .Expect(3, true)
@@ -523,7 +528,7 @@
 
   srv_stream.Read(&recv_request, tag(4));
 
-  if (GetParam().message_content.length() < 65536) {
+  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
     Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
   } else {
     Verifier(GetParam().disable_blocking)
@@ -807,7 +812,7 @@
   // up until server read is initiated. For write of send_request smaller than
   // the flow control window size, the request can take the free ride with
   // initial metadata due to coalescing, thus write tag:3 will come up here.
-  if (GetParam().message_content.length() < 65536) {
+  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
     Verifier(GetParam().disable_blocking)
         .Expect(2, true)
         .Expect(3, true)
@@ -818,7 +823,7 @@
 
   srv_stream.Read(&recv_request, tag(4));
 
-  if (GetParam().message_content.length() < 65536) {
+  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
     Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
   } else {
     Verifier(GetParam().disable_blocking)
@@ -875,7 +880,7 @@
   // up until server read is initiated. For write of send_request smaller than
   // the flow control window size, the request can take the free ride with
   // initial metadata due to coalescing, thus write tag:3 will come up here.
-  if (GetParam().message_content.length() < 65536) {
+  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
     Verifier(GetParam().disable_blocking)
         .Expect(2, true)
         .Expect(3, true)
@@ -886,7 +891,7 @@
 
   srv_stream.Read(&recv_request, tag(4));
 
-  if (GetParam().message_content.length() < 65536) {
+  if (GetParam().message_content.length() < 65536 || GetParam().inproc) {
     Verifier(GetParam().disable_blocking).Expect(4, true).Verify(cq_.get());
   } else {
     Verifier(GetParam().disable_blocking)
@@ -1223,7 +1228,9 @@
   auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
       GetParam().credentials_type, &args);
   std::shared_ptr<Channel> channel =
-      CreateCustomChannel(server_address_.str(), channel_creds, args);
+      !(GetParam().inproc)
+          ? CreateCustomChannel(server_address_.str(), channel_creds, args)
+          : server_->InProcessChannel(args);
   std::unique_ptr<grpc::testing::UnimplementedEchoService::Stub> stub;
   stub = grpc::testing::UnimplementedEchoService::NewStub(channel);
   EchoRequest send_request;
@@ -1634,13 +1641,17 @@
     // This is expected to succeed in all cases
     cli_stream->WritesDone(tag(7));
     verif.Expect(7, true);
-    got_tag = verif.Next(cq_.get(), ignore_cq_result);
+    // TODO(vjpai): Consider whether the following is too flexible
+    // or whether it should just be reset to ignore_cq_result
+    bool ignore_cq_wd_result =
+        ignore_cq_result || (server_try_cancel == CANCEL_BEFORE_PROCESSING);
+    got_tag = verif.Next(cq_.get(), ignore_cq_wd_result);
     GPR_ASSERT((got_tag == 7) || (got_tag == 11 && want_done_tag));
     if (got_tag == 11) {
       EXPECT_TRUE(srv_ctx.IsCancelled());
       want_done_tag = false;
       // Now get the other entry that we were waiting on
-      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_result), 7);
+      EXPECT_EQ(verif.Next(cq_.get(), ignore_cq_wd_result), 7);
     }
 
     // This is expected to fail in all cases i.e for all values of
@@ -1732,8 +1743,14 @@
   std::vector<grpc::string> credentials_types;
   std::vector<grpc::string> messages;
 
-  if (GetCredentialsProvider()->GetChannelCredentials(kInsecureCredentialsType,
-                                                      nullptr) != nullptr) {
+  auto insec_ok = [] {
+    // Only allow insecure credentials type when it is registered with the
+    // provider. User may create providers that do not have insecure.
+    return GetCredentialsProvider()->GetChannelCredentials(
+               kInsecureCredentialsType, nullptr) != nullptr;
+  };
+
+  if (insec_ok()) {
     credentials_types.push_back(kInsecureCredentialsType);
   }
   auto sec_list = GetCredentialsProvider()->GetSecureCredentialsTypeList();
@@ -1755,14 +1772,19 @@
   // TODO (sreek) Renable tests with health check service after the issue
   // https://github.com/grpc/grpc/issues/11223 is resolved
   for (auto health_check_service : {false}) {
-    for (auto cred = credentials_types.begin(); cred != credentials_types.end();
-         ++cred) {
-      for (auto msg = messages.begin(); msg != messages.end(); msg++) {
-        scenarios.emplace_back(false, *cred, health_check_service, *msg);
+    for (auto msg = messages.begin(); msg != messages.end(); msg++) {
+      for (auto cred = credentials_types.begin();
+           cred != credentials_types.end(); ++cred) {
+        scenarios.emplace_back(false, false, *cred, health_check_service, *msg);
         if (test_disable_blocking) {
-          scenarios.emplace_back(true, *cred, health_check_service, *msg);
+          scenarios.emplace_back(true, false, *cred, health_check_service,
+                                 *msg);
         }
       }
+      if (insec_ok()) {
+        scenarios.emplace_back(false, true, kInsecureCredentialsType,
+                               health_check_service, *msg);
+      }
     }
   }
   return scenarios;
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index d72dda3..8d12971 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -193,10 +193,11 @@
 
 class TestScenario {
  public:
-  TestScenario(bool proxy, const grpc::string& creds_type)
-      : use_proxy(proxy), credentials_type(creds_type) {}
+  TestScenario(bool proxy, bool inproc_stub, const grpc::string& creds_type)
+      : use_proxy(proxy), inproc(inproc_stub), credentials_type(creds_type) {}
   void Log() const;
   bool use_proxy;
+  bool inproc;
   // Although the below grpc::string is logically const, we can't declare
   // them const because of a limitation in the way old compilers (e.g., gcc-4.4)
   // manage vector insertion using a copy constructor
@@ -206,8 +207,9 @@
 static std::ostream& operator<<(std::ostream& out,
                                 const TestScenario& scenario) {
   return out << "TestScenario{use_proxy="
-             << (scenario.use_proxy ? "true" : "false") << ", credentials='"
-             << scenario.credentials_type << "'}";
+             << (scenario.use_proxy ? "true" : "false")
+             << ", inproc=" << (scenario.inproc ? "true" : "false")
+             << ", credentials='" << scenario.credentials_type << "'}";
 }
 
 void TestScenario::Log() const {
@@ -273,7 +275,13 @@
       args.SetUserAgentPrefix(user_agent_prefix_);
     }
     args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
-    channel_ = CreateCustomChannel(server_address_.str(), channel_creds, args);
+
+    if (!GetParam().inproc) {
+      channel_ =
+          CreateCustomChannel(server_address_.str(), channel_creds, args);
+    } else {
+      channel_ = server_->InProcessChannel(args);
+    }
   }
 
   void ResetStub() {
@@ -633,6 +641,10 @@
 }
 
 TEST_P(End2endTest, SimpleRpcWithCustomUserAgentPrefix) {
+  // User-Agent is an HTTP header for HTTP transports only
+  if (GetParam().inproc) {
+    return;
+  }
   user_agent_prefix_ = "custom_prefix";
   ResetStub();
   EchoRequest request;
@@ -1065,6 +1077,10 @@
 }
 
 TEST_P(End2endTest, ChannelState) {
+  if (GetParam().inproc) {
+    return;
+  }
+
   ResetStub();
   // Start IDLE
   EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false));
@@ -1088,7 +1104,8 @@
 
 // Takes 10s.
 TEST_P(End2endTest, ChannelStateTimeout) {
-  if (GetParam().credentials_type != kInsecureCredentialsType) {
+  if ((GetParam().credentials_type != kInsecureCredentialsType) ||
+      GetParam().inproc) {
     return;
   }
   int port = grpc_pick_unused_port_or_die();
@@ -1669,51 +1686,56 @@
 
 std::vector<TestScenario> CreateTestScenarios(bool use_proxy,
                                               bool test_insecure,
-                                              bool test_secure) {
+                                              bool test_secure,
+                                              bool test_inproc) {
   std::vector<TestScenario> scenarios;
   std::vector<grpc::string> credentials_types;
   if (test_secure) {
     credentials_types =
         GetCredentialsProvider()->GetSecureCredentialsTypeList();
   }
-  if (test_insecure) {
-    // Only add insecure credentials type when it is registered with the
+  auto insec_ok = [] {
+    // Only allow insecure credentials type when it is registered with the
     // provider. User may create providers that do not have insecure.
-    if (GetCredentialsProvider()->GetChannelCredentials(
-            kInsecureCredentialsType, nullptr) != nullptr) {
-      credentials_types.push_back(kInsecureCredentialsType);
-    }
+    return GetCredentialsProvider()->GetChannelCredentials(
+               kInsecureCredentialsType, nullptr) != nullptr;
+  };
+  if (test_insecure && insec_ok()) {
+    credentials_types.push_back(kInsecureCredentialsType);
   }
   GPR_ASSERT(!credentials_types.empty());
   for (auto it = credentials_types.begin(); it != credentials_types.end();
        ++it) {
-    scenarios.emplace_back(false, *it);
+    scenarios.emplace_back(false, false, *it);
     if (use_proxy) {
-      scenarios.emplace_back(true, *it);
+      scenarios.emplace_back(true, false, *it);
     }
   }
+  if (test_inproc && insec_ok()) {
+    scenarios.emplace_back(false, true, kInsecureCredentialsType);
+  }
   return scenarios;
 }
 
 INSTANTIATE_TEST_CASE_P(End2end, End2endTest,
                         ::testing::ValuesIn(CreateTestScenarios(false, true,
-                                                                true)));
+                                                                true, true)));
 
 INSTANTIATE_TEST_CASE_P(End2endServerTryCancel, End2endServerTryCancelTest,
                         ::testing::ValuesIn(CreateTestScenarios(false, true,
-                                                                true)));
+                                                                true, true)));
 
 INSTANTIATE_TEST_CASE_P(ProxyEnd2end, ProxyEnd2endTest,
                         ::testing::ValuesIn(CreateTestScenarios(true, true,
-                                                                true)));
+                                                                true, false)));
 
 INSTANTIATE_TEST_CASE_P(SecureEnd2end, SecureEnd2endTest,
                         ::testing::ValuesIn(CreateTestScenarios(false, false,
-                                                                true)));
+                                                                true, false)));
 
 INSTANTIATE_TEST_CASE_P(ResourceQuotaEnd2end, ResourceQuotaEnd2endTest,
                         ::testing::ValuesIn(CreateTestScenarios(false, true,
-                                                                true)));
+                                                                true, true)));
 
 }  // namespace
 }  // namespace testing
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 542df00..f990a7e 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -151,16 +151,6 @@
   std::mutex mu_;
 };
 
-class TestServiceImplDupPkg
-    : public ::grpc::testing::duplicate::EchoTestService::Service {
- public:
-  Status Echo(ServerContext* context, const EchoRequest* request,
-              EchoResponse* response) override {
-    response->set_message("no package");
-    return Status::OK;
-  }
-};
-
 template <class Service>
 class CommonStressTest {
  public:
@@ -168,63 +158,92 @@
   virtual ~CommonStressTest() {}
   virtual void SetUp() = 0;
   virtual void TearDown() = 0;
-  void ResetStub() {
-    std::shared_ptr<Channel> channel =
-        CreateChannel(server_address_.str(), InsecureChannelCredentials());
-    stub_ = grpc::testing::EchoTestService::NewStub(channel);
-  }
+  virtual void ResetStub() = 0;
   grpc::testing::EchoTestService::Stub* GetStub() { return stub_.get(); }
 
  protected:
-  void SetUpStart(ServerBuilder* builder, Service* service) {
-    int port = grpc_pick_unused_port_or_die();
-    server_address_ << "localhost:" << port;
-    // Setup server
-    builder->AddListeningPort(server_address_.str(),
-                              InsecureServerCredentials());
+  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+  std::unique_ptr<Server> server_;
+
+  virtual void SetUpStart(ServerBuilder* builder, Service* service) = 0;
+  void SetUpStartCommon(ServerBuilder* builder, Service* service) {
     builder->RegisterService(service);
     builder->SetMaxMessageSize(
         kMaxMessageSize_);  // For testing max message size.
-    builder->RegisterService(&dup_pkg_service_);
   }
   void SetUpEnd(ServerBuilder* builder) { server_ = builder->BuildAndStart(); }
   void TearDownStart() { server_->Shutdown(); }
   void TearDownEnd() {}
 
  private:
-  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
-  std::unique_ptr<Server> server_;
-  std::ostringstream server_address_;
   const int kMaxMessageSize_;
-  TestServiceImplDupPkg dup_pkg_service_;
 };
 
-class CommonStressTestSyncServer : public CommonStressTest<TestServiceImpl> {
+template <class Service>
+class CommonStressTestInsecure : public CommonStressTest<Service> {
+ public:
+  void ResetStub() override {
+    std::shared_ptr<Channel> channel =
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
+    this->stub_ = grpc::testing::EchoTestService::NewStub(channel);
+  }
+
+ protected:
+  void SetUpStart(ServerBuilder* builder, Service* service) override {
+    int port = grpc_pick_unused_port_or_die();
+    this->server_address_ << "localhost:" << port;
+    // Setup server
+    builder->AddListeningPort(server_address_.str(),
+                              InsecureServerCredentials());
+    this->SetUpStartCommon(builder, service);
+  }
+
+ private:
+  std::ostringstream server_address_;
+};
+
+template <class Service>
+class CommonStressTestInproc : public CommonStressTest<Service> {
+ public:
+  void ResetStub() override {
+    ChannelArguments args;
+    std::shared_ptr<Channel> channel = this->server_->InProcessChannel(args);
+    this->stub_ = grpc::testing::EchoTestService::NewStub(channel);
+  }
+
+ protected:
+  void SetUpStart(ServerBuilder* builder, Service* service) override {
+    this->SetUpStartCommon(builder, service);
+  }
+};
+
+template <class BaseClass>
+class CommonStressTestSyncServer : public BaseClass {
  public:
   void SetUp() override {
     ServerBuilder builder;
-    SetUpStart(&builder, &service_);
-    SetUpEnd(&builder);
+    this->SetUpStart(&builder, &service_);
+    this->SetUpEnd(&builder);
   }
   void TearDown() override {
-    TearDownStart();
-    TearDownEnd();
+    this->TearDownStart();
+    this->TearDownEnd();
   }
 
  private:
   TestServiceImpl service_;
 };
 
-class CommonStressTestAsyncServer
-    : public CommonStressTest<grpc::testing::EchoTestService::AsyncService> {
+template <class BaseClass>
+class CommonStressTestAsyncServer : public BaseClass {
  public:
   CommonStressTestAsyncServer() : contexts_(kNumAsyncServerThreads * 100) {}
   void SetUp() override {
     shutting_down_ = false;
     ServerBuilder builder;
-    SetUpStart(&builder, &service_);
+    this->SetUpStart(&builder, &service_);
     cq_ = builder.AddCompletionQueue();
-    SetUpEnd(&builder);
+    this->SetUpEnd(&builder);
     for (int i = 0; i < kNumAsyncServerThreads * 100; i++) {
       RefreshContext(i);
     }
@@ -236,7 +255,7 @@
   void TearDown() override {
     {
       std::unique_lock<std::mutex> l(mu_);
-      TearDownStart();
+      this->TearDownStart();
       shutting_down_ = true;
       cq_->Shutdown();
     }
@@ -249,7 +268,7 @@
     bool ignored_ok;
     while (cq_->Next(&ignored_tag, &ignored_ok))
       ;
-    TearDownEnd();
+    this->TearDownEnd();
   }
 
  private:
@@ -332,8 +351,13 @@
   }
 }
 
-typedef ::testing::Types<CommonStressTestSyncServer,
-                         CommonStressTestAsyncServer>
+typedef ::testing::Types<
+    CommonStressTestSyncServer<CommonStressTestInsecure<TestServiceImpl>>,
+    CommonStressTestSyncServer<CommonStressTestInproc<TestServiceImpl>>,
+    CommonStressTestAsyncServer<
+        CommonStressTestInsecure<grpc::testing::EchoTestService::AsyncService>>,
+    CommonStressTestAsyncServer<
+        CommonStressTestInproc<grpc::testing::EchoTestService::AsyncService>>>
     CommonTypes;
 TYPED_TEST_CASE(End2endTest, CommonTypes);
 TYPED_TEST(End2endTest, ThreadStress) {
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
index 1e3830a..f79db15 100644
--- a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -41,6 +41,7 @@
 static void* g_tag = (void*)(intptr_t)10;  // Some random number
 static grpc_completion_queue* g_cq;
 static grpc_event_engine_vtable g_vtable;
+static const grpc_event_engine_vtable* g_old_vtable;
 
 static void pollset_shutdown(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
                              grpc_closure* closure) {
@@ -72,7 +73,7 @@
                                 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");
+    gpr_log(GPR_DEBUG, "no-op");
     return GRPC_ERROR_NONE;
   }
 
@@ -98,7 +99,12 @@
 
 static void setup() {
   grpc_init();
+
+  /* Override the event engine with our test event engine (g_vtable); but before
+   * that, save the current event engine in g_old_vtable. We will have to set
+   * g_old_vtable back before calling grpc_shutdown() */
   init_engine_vtable();
+  g_old_vtable = grpc_get_event_engine_test_only();
   grpc_set_event_engine_test_only(&g_vtable);
 
   g_cq = grpc_completion_queue_create_for_next(NULL);
@@ -115,6 +121,10 @@
   }
 
   grpc_completion_queue_destroy(g_cq);
+
+  /* Restore the old event engine before calling grpc_shutdown */
+  grpc_set_event_engine_test_only(g_old_vtable);
+  grpc_shutdown();
 }
 
 /* A few notes about Multi-threaded benchmarks:
diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
index f420bd7..0712a40 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
@@ -414,24 +414,34 @@
     ->Apply(StreamingPingPongArgs);
 BENCHMARK_TEMPLATE(BM_StreamingPingPong, TCP, NoOpMutator, NoOpMutator)
     ->Apply(StreamingPingPongArgs);
+BENCHMARK_TEMPLATE(BM_StreamingPingPong, InProcess, NoOpMutator, NoOpMutator)
+    ->Apply(StreamingPingPongArgs);
 
 BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, InProcessCHTTP2, NoOpMutator,
                    NoOpMutator)
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, TCP, NoOpMutator, NoOpMutator)
     ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, InProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Range(0, 128 * 1024 * 1024);
 
 BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinInProcessCHTTP2, NoOpMutator,
                    NoOpMutator)
     ->Apply(StreamingPingPongArgs);
 BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinTCP, NoOpMutator, NoOpMutator)
     ->Apply(StreamingPingPongArgs);
+BENCHMARK_TEMPLATE(BM_StreamingPingPong, MinInProcess, NoOpMutator, NoOpMutator)
+    ->Apply(StreamingPingPongArgs);
 
 BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinInProcessCHTTP2, NoOpMutator,
                    NoOpMutator)
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinTCP, NoOpMutator, NoOpMutator)
     ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_StreamingPingPongMsgs, MinInProcess, NoOpMutator,
+                   NoOpMutator)
+    ->Range(0, 128 * 1024 * 1024);
 
 // Generate Args for StreamingPingPongWithCoalescingApi benchmarks. Currently
 // generates args for only "small streams" (i.e streams with 0, 1 or 2 messages)
@@ -459,6 +469,12 @@
 BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, MinInProcessCHTTP2,
                    NoOpMutator, NoOpMutator)
     ->Apply(StreamingPingPongWithCoalescingApiArgs);
+BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, InProcess,
+                   NoOpMutator, NoOpMutator)
+    ->Apply(StreamingPingPongWithCoalescingApiArgs);
+BENCHMARK_TEMPLATE(BM_StreamingPingPongWithCoalescingApi, MinInProcess,
+                   NoOpMutator, NoOpMutator)
+    ->Apply(StreamingPingPongWithCoalescingApiArgs);
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
index fc2d67f..6fbf9da 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
@@ -173,6 +173,8 @@
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, UDS)
     ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcess)
+    ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, SockPair)
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, InProcessCHTTP2)
@@ -181,16 +183,20 @@
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, UDS)
     ->Range(0, 128 * 1024 * 1024);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcess)
+    ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, SockPair)
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, InProcessCHTTP2)
     ->Range(0, 128 * 1024 * 1024);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinTCP)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinUDS)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinInProcess)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinSockPair)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamClientToServer, MinInProcessCHTTP2)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinTCP)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinUDS)->Arg(0);
+BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinInProcess)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinSockPair)->Arg(0);
 BENCHMARK_TEMPLATE(BM_PumpStreamServerToClient, MinInProcessCHTTP2)->Arg(0);
 
diff --git a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
index ee2d5ec..9af7512 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
@@ -132,6 +132,10 @@
     ->Args({0, 0});
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinUDS, NoOpMutator, NoOpMutator)
     ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator, NoOpMutator)
+    ->Apply(SweepSizesArgs);
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinInProcess, NoOpMutator, NoOpMutator)
+    ->Apply(SweepSizesArgs);
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, SockPair, NoOpMutator, NoOpMutator)
     ->Args({0, 0});
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, MinSockPair, NoOpMutator, NoOpMutator)
@@ -191,6 +195,56 @@
 BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcessCHTTP2, NoOpMutator,
                    Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
     ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<10>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<31>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<100>, 1>,
+                   NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<10>, 2>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<31>, 2>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomBinaryMetadata<100>, 2>,
+                   NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<10>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<31>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomBinaryMetadata<100>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<10>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<31>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess,
+                   Client_AddMetadata<RandomAsciiMetadata<100>, 1>, NoOpMutator)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<31>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<100>, 1>)
+    ->Args({0, 0});
+BENCHMARK_TEMPLATE(BM_UnaryPingPong, InProcess, NoOpMutator,
+                   Server_AddInitialMetadata<RandomAsciiMetadata<10>, 100>)
+    ->Args({0, 0});
 
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index 2320086..5477b86 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -66,14 +66,21 @@
   FullstackFixture(Service* service, const FixtureConfiguration& config,
                    const grpc::string& address) {
     ServerBuilder b;
-    b.AddListeningPort(address, InsecureServerCredentials());
+    if (address.length() > 0) {
+      b.AddListeningPort(address, InsecureServerCredentials());
+    }
     cq_ = b.AddCompletionQueue(true);
     b.RegisterService(service);
     config.ApplyCommonServerBuilderConfig(&b);
     server_ = b.BuildAndStart();
     ChannelArguments args;
     config.ApplyCommonChannelArguments(&args);
-    channel_ = CreateCustomChannel(address, InsecureChannelCredentials(), args);
+    if (address.length() > 0) {
+      channel_ =
+          CreateCustomChannel(address, InsecureChannelCredentials(), args);
+    } else {
+      channel_ = server_->InProcessChannel(args);
+    }
   }
 
   virtual ~FullstackFixture() {
@@ -139,6 +146,15 @@
   }
 };
 
+class InProcess : public FullstackFixture {
+ public:
+  InProcess(Service* service,
+            const FixtureConfiguration& fixture_configuration =
+                FixtureConfiguration())
+      : FullstackFixture(service, fixture_configuration, "") {}
+  ~InProcess() {}
+};
+
 class EndpointPairFixture : public BaseFixture {
  public:
   EndpointPairFixture(Service* service, grpc_endpoint_pair endpoints,
@@ -279,6 +295,7 @@
 
 typedef MinStackize<TCP> MinTCP;
 typedef MinStackize<UDS> MinUDS;
+typedef MinStackize<InProcess> MinInProcess;
 typedef MinStackize<SockPair> MinSockPair;
 typedef MinStackize<InProcessCHTTP2> MinInProcessCHTTP2;
 
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 766c20f..4c6c656 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1047,6 +1047,9 @@
 src/core/ext/transport/chttp2/transport/varint.c \
 src/core/ext/transport/chttp2/transport/varint.h \
 src/core/ext/transport/chttp2/transport/writing.c \
+src/core/ext/transport/inproc/inproc_plugin.c \
+src/core/ext/transport/inproc/inproc_transport.c \
+src/core/ext/transport/inproc/inproc_transport.h \
 src/core/lib/README.md \
 src/core/lib/channel/README.md \
 src/core/lib/channel/channel_args.c \
diff --git a/tools/internal_ci/linux/grpc_basictests_multilang.cfg b/tools/internal_ci/linux/grpc_basictests_multilang.cfg
index 0a1afa2..be099d7 100644
--- a/tools/internal_ci/linux/grpc_basictests_multilang.cfg
+++ b/tools/internal_ci/linux/grpc_basictests_multilang.cfg
@@ -25,5 +25,5 @@
 
 env_vars {
   key: "RUN_TESTS_FLAGS"
-  value: "-f basictests linux multilang --inner_jobs 16 -j 1 --internal_ci --bq_result_table aggregate_results"
+  value: "-f basictests linux multilang --inner_jobs 16 -j 2 --internal_ci --bq_result_table aggregate_results"
 }
diff --git a/tools/mkowners/mkowners.py b/tools/mkowners/mkowners.py
index 18afe3a..2ccedfc 100755
--- a/tools/mkowners/mkowners.py
+++ b/tools/mkowners/mkowners.py
@@ -126,30 +126,71 @@
 def full_dir(rules_dir, sub_path):
   return os.path.join(rules_dir, sub_path) if rules_dir != '.' else sub_path
 
-def glob_intersect(g1, g2):
-  if not g2:
-    return all(c == '*' for c in g1)
-  if not g1:
-    return all(c == '*' for c in g2)
-  c1, *t1 = g1
-  c2, *t2 = g2
-  if c1 == '*':
-    return glob_intersect(g1, t2) or glob_intersect(t1, g2)
-  if c2 == '*':
-    return glob_intersect(t1, g2) or glob_intersect(g1, t2)
-  return c1 == c2 and glob_intersect(t1, t2)
+# glob using git
+gg_cache = {}
+def git_glob(glob):
+  global gg_cache
+  if glob in gg_cache: return gg_cache[glob]
+  r = set(subprocess
+      .check_output(['git', 'ls-files', os.path.join(git_root, glob)])
+      .decode('utf-8')
+      .strip()
+      .splitlines())
+  gg_cache[glob] = r
+  return r
+
+def expand_directives(root, directives):
+  globs = collections.OrderedDict()
+  # build a table of glob --> owners
+  for directive in directives:
+    for glob in directive.globs or ['**']:
+      if glob not in globs:
+        globs[glob] = []
+      if directive.who not in globs[glob]:
+        globs[glob].append(directive.who)
+  # expand owners for intersecting globs
+  sorted_globs = sorted(globs.keys(),
+                        key=lambda g: len(git_glob(full_dir(root, g))),
+                        reverse=True)
+  out_globs = collections.OrderedDict()
+  for glob_add in sorted_globs:
+    who_add = globs[glob_add]
+    pre_items = [i for i in out_globs.items()]
+    out_globs[glob_add] = who_add.copy()
+    for glob_have, who_have in pre_items:
+      files_add = git_glob(full_dir(root, glob_add))
+      files_have = git_glob(full_dir(root, glob_have))
+      intersect = files_have.intersection(files_add)
+      if intersect:
+        for f in sorted(files_add): # sorted to ensure merge stability
+          if f not in intersect:
+            print("X", root, glob_add, glob_have)
+            out_globs[os.path.relpath(f, start=root)] = who_add
+        for who in who_have:
+          if who not in out_globs[glob_add]:
+            out_globs[glob_add].append(who)
+  return out_globs
 
 def add_parent_to_globs(parent, globs, globs_dir):
   if not parent: return
   for owners in owners_data:
     if owners.dir == parent:
-      for directive in owners.directives:
-        for dglob in directive.globs or ['**']:
-          for gglob, glob in globs.items():
-            if glob_intersect(full_dir(globs_dir, gglob),
-                              full_dir(owners.dir, dglob)):
-              if directive.who not in glob:
-                glob.append(directive.who)
+      owners_globs = expand_directives(owners.dir, owners.directives)
+      for oglob, oglob_who in owners_globs.items():
+        for gglob, gglob_who in globs.items():
+          files_parent = git_glob(full_dir(owners.dir, oglob))
+          files_child = git_glob(full_dir(globs_dir, gglob))
+          intersect = files_parent.intersection(files_child)
+          gglob_who_orig = gglob_who.copy()
+          if intersect:
+            for f in sorted(files_child): # sorted to ensure merge stability
+              if f not in intersect:
+                print("Y", full_dir(owners.dir, oglob), full_dir(globs_dir, gglob))
+                who = gglob_who_orig.copy()
+                globs[os.path.relpath(f, start=globs_dir)] = who
+            for who in oglob_who:
+              if who not in gglob_who:
+                gglob_who.append(who)
       add_parent_to_globs(owners.parent, globs, globs_dir)
       return
   assert(False)
@@ -160,19 +201,30 @@
   out.write('# Auto-generated by the tools/mkowners/mkowners.py tool\n')
   out.write('# Uses OWNERS files in different modules throughout the\n')
   out.write('# repository as the source of truth for module ownership.\n')
+  written_globs = []
   while todo:
     head, *todo = todo
     if head.parent and not head.parent in done:
       todo.append(head)
       continue
-    globs = collections.OrderedDict()
-    for directive in head.directives:
-      for glob in directive.globs or ['**']:
-        if glob not in globs:
-          globs[glob] = []
-        globs[glob].append(directive.who)
+    globs = expand_directives(head.dir, head.directives)
     add_parent_to_globs(head.parent, globs, head.dir)
     for glob, owners in globs.items():
-      out.write('/%s %s\n' % (
-          full_dir(head.dir, glob), ' '.join(owners)))
+      skip = False
+      for glob1, owners1, dir1 in reversed(written_globs):
+        files = git_glob(full_dir(head.dir, glob))
+        files1 = git_glob(full_dir(dir1, glob1))
+        intersect = files.intersection(files1)
+        if files == intersect:
+          if sorted(owners) == sorted(owners1):
+            skip = True # nothing new in this rule
+            break
+        elif intersect:
+          # continuing would cause a semantic change since some files are
+          # affected differently by this rule and CODEOWNERS is order dependent
+          break
+      if not skip:
+        out.write('/%s %s\n' % (
+            full_dir(head.dir, glob), ' '.join(owners)))
+        written_globs.append((glob, owners, head.dir))
     done.add(head.dir)
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 02562bf..0a91a0c 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -5196,6 +5196,24 @@
   }, 
   {
     "deps": [
+      "end2end_tests", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "inproc_test", 
+    "src": [
+      "test/core/end2end/fixtures/inproc.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "end2end_nosec_tests", 
       "gpr", 
       "gpr_test_util", 
@@ -5448,6 +5466,24 @@
   }, 
   {
     "deps": [
+      "end2end_nosec_tests", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc_test_util_unsecure", 
+      "grpc_unsecure"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "inproc_nosec_test", 
+    "src": [
+      "test/core/end2end/fixtures/inproc.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
       "gpr", 
       "gpr_test_util", 
       "grpc", 
@@ -5731,6 +5767,7 @@
       "grpc_transport_chttp2_client_secure", 
       "grpc_transport_chttp2_server_insecure", 
       "grpc_transport_chttp2_server_secure", 
+      "grpc_transport_inproc", 
       "grpc_workaround_cronet_compression_filter"
     ], 
     "headers": [], 
@@ -5836,6 +5873,7 @@
       "grpc_server_backward_compatibility", 
       "grpc_transport_chttp2_client_insecure", 
       "grpc_transport_chttp2_server_insecure", 
+      "grpc_transport_inproc", 
       "grpc_workaround_cronet_compression_filter"
     ], 
     "headers": [], 
@@ -8781,6 +8819,25 @@
   {
     "deps": [
       "gpr", 
+      "grpc_base"
+    ], 
+    "headers": [
+      "src/core/ext/transport/inproc/inproc_transport.h"
+    ], 
+    "is_filegroup": true, 
+    "language": "c", 
+    "name": "grpc_transport_inproc", 
+    "src": [
+      "src/core/ext/transport/inproc/inproc_plugin.c", 
+      "src/core/ext/transport/inproc/inproc_transport.c", 
+      "src/core/ext/transport/inproc/inproc_transport.h"
+    ], 
+    "third_party": false, 
+    "type": "filegroup"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "grpc_base", 
       "grpc_server_backward_compatibility"
     ], 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index e44bf0e..82437c9 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -28687,6 +28687,972 @@
     "exclude_iomgrs": [], 
     "flaky": false, 
     "language": "c", 
+    "name": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_round_trip"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "authority_not_supported"
+    ], 
+    "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", 
@@ -45139,6 +46105,949 @@
   }, 
   {
     "args": [
+      "authority_not_supported"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
+      "cancel_after_round_trip"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_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": "inproc_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "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, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"security_params\": null, \"threads_per_cq\": 0, \"server_type\": \"ASYNC_SERVER\"}, \"num_clients\": 1, \"client_config\": {\"security_params\": null, \"channel_args\": [{\"str_value\": \"throughput\", \"name\": \"grpc.optimization_target\"}], \"async_client_threads\": 0, \"outstanding_rpcs_per_channel\": 100, \"rpc_type\": \"UNARY\", \"payload_config\": {\"simple_params\": {\"resp_size\": 1048576, \"req_size\": 1048576}}, \"client_channels\": 1, \"threads_per_cq\": 0, \"load_params\": {\"closed_loop\": {}}, \"client_type\": \"ASYNC_CLIENT\", \"histogram_params\": {\"max_possible\": 60000000000.0, \"resolution\": 0.01}}}]}"
     ], 
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index b7696a9..3bcc832 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -1166,6 +1166,30 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inproc_nosec_test", "vcxproj\test/end2end/fixtures\inproc_nosec_test\inproc_nosec_test.vcxproj", "{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}"
+	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}") = "inproc_test", "vcxproj\test/end2end/fixtures\inproc_test\inproc_test.vcxproj", "{59BB50B7-2E76-5EAA-781E-53228520635D}"
+	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}") = "invalid_call_argument_test", "vcxproj\test\invalid_call_argument_test\invalid_call_argument_test.vcxproj", "{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -3489,6 +3513,38 @@
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release-DLL|Win32.Build.0 = Release|Win32
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release-DLL|x64.ActiveCfg = Release|x64
 		{6756895E-05BF-8CC7-58F2-868DF0C0300C}.Release-DLL|x64.Build.0 = Release|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug|x64.ActiveCfg = Debug|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release|Win32.ActiveCfg = Release|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release|x64.ActiveCfg = Release|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug|Win32.Build.0 = Debug|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug|x64.Build.0 = Debug|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release|Win32.Build.0 = Release|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release|x64.Build.0 = Release|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Debug-DLL|x64.Build.0 = Debug|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release-DLL|Win32.Build.0 = Release|Win32
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release-DLL|x64.ActiveCfg = Release|x64
+		{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}.Release-DLL|x64.Build.0 = Release|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug|x64.ActiveCfg = Debug|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release|Win32.ActiveCfg = Release|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release|x64.ActiveCfg = Release|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug|Win32.Build.0 = Debug|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug|x64.Build.0 = Debug|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release|Win32.Build.0 = Release|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release|x64.Build.0 = Release|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Debug-DLL|x64.Build.0 = Debug|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release-DLL|Win32.Build.0 = Release|Win32
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release-DLL|x64.ActiveCfg = Release|x64
+		{59BB50B7-2E76-5EAA-781E-53228520635D}.Release-DLL|x64.Build.0 = Release|x64
 		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug|Win32.ActiveCfg = Debug|Win32
 		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Debug|x64.ActiveCfg = Debug|x64
 		{C32CA8A3-58E6-8EB9-B72F-C295547D36A6}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index f9badbb..112f3ec 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -480,6 +480,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb_channel.h" />
@@ -937,6 +938,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\grpclb.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index f3e997e..5c29e58 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -628,6 +628,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create_posix.c">
       <Filter>src\core\ext\transport\chttp2\client\insecure</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
+      <Filter>src\core\ext\transport\inproc</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
+      <Filter>src\core\ext\transport\inproc</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.c">
       <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClCompile>
@@ -1385,6 +1391,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\chttp2_connector.h">
       <Filter>src\core\ext\transport\chttp2\client</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h">
+      <Filter>src\core\ext\transport\inproc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\lb_policy\grpclb\client_load_reporting_filter.h">
       <Filter>src\core\ext\filters\client_channel\lb_policy\grpclb</Filter>
     </ClInclude>
@@ -1634,6 +1643,9 @@
     <Filter Include="src\core\ext\transport\chttp2\transport">
       <UniqueIdentifier>{6f34254e-e69f-c9b4-156d-5024bade5408}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\transport\inproc">
+      <UniqueIdentifier>{fb9e878e-fc50-40af-7646-074229a9d676}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\lib">
       <UniqueIdentifier>{5b2ded3f-84a5-f6b4-2060-286c7d1dc945}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 3a865f3..730ac01 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -445,6 +445,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\subchannel_index.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\uri_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_wrapper.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\fake\fake_resolver.h" />
@@ -844,6 +845,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver_posix.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 0310ebc..427352e 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -541,6 +541,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.c">
       <Filter>src\core\ext\filters\deadline</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_plugin.c">
+      <Filter>src\core\ext\transport\inproc</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.c">
+      <Filter>src\core\ext\transport\inproc</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\dns_resolver_ares.c">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClCompile>
@@ -1220,6 +1226,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\deadline\deadline_filter.h">
       <Filter>src\core\ext\filters\deadline</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\inproc\inproc_transport.h">
+      <Filter>src\core\ext\transport\inproc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\filters\client_channel\resolver\dns\c_ares\grpc_ares_ev_driver.h">
       <Filter>src\core\ext\filters\client_channel\resolver\dns\c_ares</Filter>
     </ClInclude>
@@ -1463,6 +1472,9 @@
     <Filter Include="src\core\ext\transport\chttp2\transport">
       <UniqueIdentifier>{45b20f28-376c-9dea-1800-8a0193411946}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core\ext\transport\inproc">
+      <UniqueIdentifier>{287a62fa-b646-5062-49c4-9e7bd5bc5b96}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\core\lib">
       <UniqueIdentifier>{8bd5b461-bff8-6aa8-b5a6-85da2834eb8a}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/inproc_nosec_test/inproc_nosec_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/inproc_nosec_test/inproc_nosec_test.vcxproj
new file mode 100644
index 0000000..7850867
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/inproc_nosec_test/inproc_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>{D0D0CAE5-3D8C-390E-0F2F-58312AEADC32}</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>inproc_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>inproc_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\inproc.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/inproc_nosec_test/inproc_nosec_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/inproc_nosec_test/inproc_nosec_test.vcxproj.filters
new file mode 100644
index 0000000..25ffa17
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/inproc_nosec_test/inproc_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\inproc.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{ed71b5b3-f12c-a50c-1848-91bc295dc7a6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{89470314-c22a-c997-e533-5d1e04174120}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{eb7f58b2-73e3-5556-41ca-b301f39a61eb}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end\fixtures">
+      <UniqueIdentifier>{c6974b84-e7ab-3022-7a93-cb206fd189bc}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/fixtures/inproc_test/inproc_test.vcxproj b/vsprojects/vcxproj/test/end2end/fixtures/inproc_test/inproc_test.vcxproj
new file mode 100644
index 0000000..7d6d143
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/inproc_test/inproc_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>{59BB50B7-2E76-5EAA-781E-53228520635D}</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>inproc_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>inproc_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\inproc.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/inproc_test/inproc_test.vcxproj.filters b/vsprojects/vcxproj/test/end2end/fixtures/inproc_test/inproc_test.vcxproj.filters
new file mode 100644
index 0000000..6db8387
--- /dev/null
+++ b/vsprojects/vcxproj/test/end2end/fixtures/inproc_test/inproc_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\inproc.c">
+      <Filter>test\core\end2end\fixtures</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{18db9e76-ea71-0740-617f-ab04f151392c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{8c1ba9f9-2af8-e515-d621-ff46b37b4838}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end">
+      <UniqueIdentifier>{16f70dc0-364b-4d2b-edf6-dfa731c168d7}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\end2end\fixtures">
+      <UniqueIdentifier>{854c88c3-4f3d-7ef0-6a08-d4f84a0ff92e}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+