Merge branch 'master' into server_channel_affinity
diff --git a/examples/cpp/helloworld/Makefile b/examples/cpp/helloworld/Makefile
index 4b1867e..470b835 100644
--- a/examples/cpp/helloworld/Makefile
+++ b/examples/cpp/helloworld/Makefile
@@ -32,7 +32,7 @@
 CXX = g++
 CPPFLAGS += -I/usr/local/include -pthread
 CXXFLAGS += -std=c++11
-LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
+LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
 PROTOC = protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
 GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
diff --git a/examples/cpp/route_guide/Makefile b/examples/cpp/route_guide/Makefile
index 0fbb0a8..11f2a00 100644
--- a/examples/cpp/route_guide/Makefile
+++ b/examples/cpp/route_guide/Makefile
@@ -32,7 +32,7 @@
 CXX = g++
 CPPFLAGS += -I/usr/local/include -pthread
 CXXFLAGS += -std=c++11
-LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
+LDFLAGS += -L/usr/local/lib `pkg-config --libs grpc++` -lprotobuf -lpthread -ldl
 PROTOC = protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
 GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
diff --git a/examples/python/README.md b/examples/python/README.md
index b57da8f..9992baa 100644
--- a/examples/python/README.md
+++ b/examples/python/README.md
@@ -8,12 +8,19 @@
 
 
 Install gRPC:
-  ```sh
+```sh
   $ pip install grpcio
 ```
 Or, to install it system wide:
 ```sh
-	$ sudo pip install grpcio
+  $ sudo pip install grpcio
+```
+
+If you're on Windows, make sure you installed the `pip.exe` component when you
+installed Python. Invoke as above but with `pip.exe` instead of `pip` (you may
+also need to invoke from a `cmd.exe` ran as administrator):
+```sh
+  $ pip.exe install grpcio
 ```
 
 Download the example
diff --git a/grpc.def b/grpc.def
index 98acf10..3477bd9 100644
--- a/grpc.def
+++ b/grpc.def
@@ -87,6 +87,7 @@
     grpc_header_key_is_legal
     grpc_header_nonbin_value_is_legal
     grpc_is_binary_header
+    grpc_call_error_to_string
     grpc_auth_property_iterator_next
     grpc_auth_context_property_iterator
     grpc_auth_context_peer_identity
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index ee15b9d..6f7a67b 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -393,6 +393,9 @@
 /** Check whether a metadata key corresponds to a binary value */
 GRPCAPI int grpc_is_binary_header(const char *key, size_t length);
 
+/** Convert grpc_call_error values to a string */
+GRPCAPI const char *grpc_call_error_to_string(grpc_call_error error);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/compiler/config.h b/src/compiler/config.h
index a534b11..d8b9581 100644
--- a/src/compiler/config.h
+++ b/src/compiler/config.h
@@ -70,6 +70,11 @@
 #define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain
 #endif
 
+#ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER
+#include <google/protobuf/compiler/code_generator.h>
+#define GRPC_CUSTOM_PARSEGENERATORPARAMETER ::google::protobuf::compiler::ParseGeneratorParameter
+#endif
+
 namespace grpc {
 namespace protobuf {
 typedef GRPC_CUSTOM_DESCRIPTOR Descriptor;
@@ -85,6 +90,11 @@
                              const CodeGenerator* generator) {
   return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator);
 }
+static inline void ParseGeneratorParameter(const string& parameter,
+    std::vector<std::pair<string, string> >* options) {
+  GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options);
+}
+
 }  // namespace compiler
 namespace io {
 typedef GRPC_CUSTOM_PRINTER Printer;
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index 4def6c5..ac0fee1 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -52,6 +52,7 @@
 using grpc::protobuf::io::Printer;
 using grpc::protobuf::io::StringOutputStream;
 using grpc_generator::MethodType;
+using grpc_generator::GetCppComments;
 using grpc_generator::GetMethodType;
 using grpc_generator::METHODTYPE_NO_STREAMING;
 using grpc_generator::METHODTYPE_CLIENT_STREAMING;
@@ -65,6 +66,56 @@
 namespace grpc_csharp_generator {
 namespace {
 
+// This function is a massaged version of
+// https://github.com/google/protobuf/blob/master/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc
+// Currently, we cannot easily reuse the functionality as
+// google/protobuf/compiler/csharp/csharp_doc_comment.h is not a public header.
+// TODO(jtattermusch): reuse the functionality from google/protobuf.
+void GenerateDocCommentBodyImpl(grpc::protobuf::io::Printer* printer, grpc::protobuf::SourceLocation location) {
+    grpc::string comments = location.leading_comments.empty() ?
+        location.trailing_comments : location.leading_comments;
+  if (comments.empty()) {
+    return;
+  }
+  // XML escaping... no need for apostrophes etc as the whole text is going to be a child
+  // node of a summary element, not part of an attribute.
+  comments = grpc_generator::StringReplace(comments, "&", "&amp;", true);
+  comments = grpc_generator::StringReplace(comments, "<", "&lt;", true);
+
+  std::vector<grpc::string> lines;
+  grpc_generator::Split(comments, '\n', &lines);
+  // TODO: We really should work out which part to put in the summary and which to put in the remarks...
+  // but that needs to be part of a bigger effort to understand the markdown better anyway.
+  printer->Print("/// <summary>\n");
+  bool last_was_empty = false;
+  // We squash multiple blank lines down to one, and remove any trailing blank lines. We need
+  // to preserve the blank lines themselves, as this is relevant in the markdown.
+  // Note that we can't remove leading or trailing whitespace as *that's* relevant in markdown too.
+  // (We don't skip "just whitespace" lines, either.)
+  for (std::vector<grpc::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
+    grpc::string line = *it;
+    if (line.empty()) {
+      last_was_empty = true;
+    } else {
+      if (last_was_empty) {
+          printer->Print("///\n");
+      }
+      last_was_empty = false;
+      printer->Print("/// $line$\n", "line", *it);
+    }
+  }
+  printer->Print("/// </summary>\n");
+}
+
+template <typename DescriptorType>
+void GenerateDocCommentBody(
+  grpc::protobuf::io::Printer* printer, const DescriptorType* descriptor) {
+  grpc::protobuf::SourceLocation location;
+  if (descriptor->GetSourceLocation(&location)) {
+    GenerateDocCommentBodyImpl(printer, location);
+  }
+}
+
 std::string GetServiceClassName(const ServiceDescriptor* service) {
   return service->name();
 }
@@ -123,6 +174,10 @@
   return GetClassName(method->input_type()) + " request, ";
 }
 
+std::string GetAccessLevel(bool internal_access) {
+  return internal_access ? "internal" : "public";
+}
+
 std::string GetMethodReturnTypeClient(const MethodDescriptor *method) {
   switch (GetMethodType(method)) {
     case METHODTYPE_NO_STREAMING:
@@ -238,7 +293,7 @@
 void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) {
   std::ostringstream index;
   index << service->index();
-  out->Print("// service descriptor\n");
+  out->Print("/// <summary>Service descriptor</summary>\n");
   out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n");
   out->Print("{\n");
   out->Print("  get { return $umbrella$.Descriptor.Services[$index$]; }\n",
@@ -249,7 +304,8 @@
 }
 
 void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// client interface\n");
+  out->Print("/// <summary>Client for $servicename$</summary>\n",
+             "servicename", GetServiceClassName(service));
   out->Print("[System.Obsolete(\"Client side interfaced will be removed "
              "in the next release. Use client class directly.\")]\n");
   out->Print("public interface $name$\n", "name",
@@ -262,6 +318,7 @@
 
     if (method_type == METHODTYPE_NO_STREAMING) {
       // unary calls have an extra synchronous stub method
+      GenerateDocCommentBody(out, method);
       out->Print(
           "$response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
           "methodname", method->name(), "request",
@@ -269,6 +326,7 @@
           GetClassName(method->output_type()));
 
       // overload taking CallOptions as a param
+      GenerateDocCommentBody(out, method);
       out->Print(
           "$response$ $methodname$($request$ request, CallOptions options);\n",
           "methodname", method->name(), "request",
@@ -280,6 +338,7 @@
     if (method_type == METHODTYPE_NO_STREAMING) {
       method_name += "Async";  // prevent name clash with synchronous method.
     }
+    GenerateDocCommentBody(out, method);
     out->Print(
         "$returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));\n",
         "methodname", method_name, "request_maybe",
@@ -287,6 +346,7 @@
         GetMethodReturnTypeClient(method));
 
     // overload taking CallOptions as a param
+    GenerateDocCommentBody(out, method);
     out->Print(
         "$returntype$ $methodname$($request_maybe$CallOptions options);\n",
         "methodname", method_name, "request_maybe",
@@ -299,7 +359,8 @@
 }
 
 void GenerateServerInterface(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// server-side interface\n");
+  out->Print("/// <summary>Interface of server-side implementations of $servicename$</summary>\n",
+             "servicename", GetServiceClassName(service));
   out->Print("[System.Obsolete(\"Service implementations should inherit"
       " from the generated abstract base class instead.\")]\n");
   out->Print("public interface $name$\n", "name",
@@ -308,6 +369,7 @@
   out->Indent();
   for (int i = 0; i < service->method_count(); i++) {
     const MethodDescriptor *method = service->method(i);
+    GenerateDocCommentBody(out, method);
     out->Print(
         "$returntype$ $methodname$($request$$response_stream_maybe$, "
         "ServerCallContext context);\n",
@@ -322,13 +384,15 @@
 }
 
 void GenerateServerClass(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// server-side abstract class\n");
+  out->Print("/// <summary>Base class for server-side implementations of $servicename$</summary>\n",
+             "servicename", GetServiceClassName(service));
   out->Print("public abstract class $name$\n", "name",
              GetServerClassName(service));
   out->Print("{\n");
   out->Indent();
   for (int i = 0; i < service->method_count(); i++) {
     const MethodDescriptor *method = service->method(i);
+    GenerateDocCommentBody(out, method);
     out->Print(
         "public virtual $returntype$ $methodname$($request$$response_stream_maybe$, "
         "ServerCallContext context)\n",
@@ -349,7 +413,8 @@
 }
 
 void GenerateClientStub(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// client stub\n");
+  out->Print("/// <summary>Client for $servicename$</summary>\n",
+             "servicename", GetServiceClassName(service));
   out->Print("#pragma warning disable 0618\n");
   out->Print(
       "public class $name$ : ClientBase<$name$>, $interface$\n",
@@ -388,6 +453,7 @@
 
     if (method_type == METHODTYPE_NO_STREAMING) {
       // unary calls have an extra synchronous stub method
+      GenerateDocCommentBody(out, method);
       out->Print("public virtual $response$ $methodname$($request$ request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
@@ -400,6 +466,7 @@
       out->Print("}\n");
 
       // overload taking CallOptions as a param
+      GenerateDocCommentBody(out, method);
       out->Print("public virtual $response$ $methodname$($request$ request, CallOptions options)\n",
           "methodname", method->name(), "request",
           GetClassName(method->input_type()), "response",
@@ -416,6 +483,7 @@
     if (method_type == METHODTYPE_NO_STREAMING) {
       method_name += "Async";  // prevent name clash with synchronous method.
     }
+    GenerateDocCommentBody(out, method);
     out->Print(
             "public virtual $returntype$ $methodname$($request_maybe$Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))\n",
             "methodname", method_name, "request_maybe",
@@ -431,6 +499,7 @@
     out->Print("}\n");
 
     // overload taking CallOptions as a param
+    GenerateDocCommentBody(out, method);
     out->Print(
         "public virtual $returntype$ $methodname$($request_maybe$CallOptions options)\n",
         "methodname", method_name, "request_maybe",
@@ -481,7 +550,7 @@
 void GenerateBindServiceMethod(Printer* out, const ServiceDescriptor *service,
                                bool use_server_class) {
   out->Print(
-      "// creates service definition that can be registered with a server\n");
+      "/// <summary>Creates service definition that can be registered with a server</summary>\n");
   out->Print("#pragma warning disable 0618\n");
   out->Print(
       "public static ServerServiceDefinition BindService($interface$ serviceImpl)\n",
@@ -515,7 +584,8 @@
 }
 
 void GenerateNewStubMethods(Printer* out, const ServiceDescriptor *service) {
-  out->Print("// creates a new client\n");
+  out->Print("/// <summary>Creates a new client for $servicename$</summary>\n",
+             "servicename", GetServiceClassName(service));
   out->Print("public static $classname$ NewClient(Channel channel)\n",
              "classname", GetClientClassName(service));
   out->Print("{\n");
@@ -527,8 +597,12 @@
   out->Print("\n");
 }
 
-void GenerateService(Printer* out, const ServiceDescriptor *service) {
-  out->Print("public static class $classname$\n", "classname",
+void GenerateService(Printer* out, const ServiceDescriptor *service,
+                     bool generate_client, bool generate_server,
+                     bool internal_access) {
+  GenerateDocCommentBody(out, service);
+  out->Print("$access_level$ static class $classname$\n", "access_level",
+             GetAccessLevel(internal_access), "classname",
              GetServiceClassName(service));
   out->Print("{\n");
   out->Indent();
@@ -542,13 +616,22 @@
     GenerateStaticMethodField(out, service->method(i));
   }
   GenerateServiceDescriptorProperty(out, service);
-  GenerateClientInterface(out, service);
-  GenerateServerInterface(out, service);
-  GenerateServerClass(out, service);
-  GenerateClientStub(out, service);
-  GenerateBindServiceMethod(out, service, false);
-  GenerateBindServiceMethod(out, service, true);
-  GenerateNewStubMethods(out, service);
+
+  if (generate_client) {
+    GenerateClientInterface(out, service);
+  }
+  if (generate_server) {
+    GenerateServerInterface(out, service);
+    GenerateServerClass(out, service);
+  }
+  if (generate_client) {
+    GenerateClientStub(out, service);
+    GenerateNewStubMethods(out, service);
+  }
+  if (generate_server) {
+    GenerateBindServiceMethod(out, service, false);
+    GenerateBindServiceMethod(out, service, true);
+  }
 
   out->Outdent();
   out->Print("}\n");
@@ -556,7 +639,8 @@
 
 }  // anonymous namespace
 
-grpc::string GetServices(const FileDescriptor *file) {
+grpc::string GetServices(const FileDescriptor *file, bool generate_client,
+                         bool generate_server, bool internal_access) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -573,6 +657,14 @@
     // Write out a file header.
     out.Print("// Generated by the protocol buffer compiler.  DO NOT EDIT!\n");
     out.Print("// source: $filename$\n", "filename", file->name());
+
+    // use C++ style as there are no file-level XML comments in .NET
+    grpc::string leading_comments = GetCppComments(file, true);
+    if (!leading_comments.empty()) {
+      out.Print("// Original file comments:\n");
+      out.Print(leading_comments.c_str());
+    }
+
     out.Print("#region Designer generated code\n");
     out.Print("\n");
     out.Print("using System;\n");
@@ -584,7 +676,8 @@
     out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file));
     out.Indent();
     for (int i = 0; i < file->service_count(); i++) {
-      GenerateService(&out, file->service(i));
+      GenerateService(&out, file->service(i), generate_client, generate_server,
+                      internal_access);
     }
     out.Outdent();
     out.Print("}\n");
diff --git a/src/compiler/csharp_generator.h b/src/compiler/csharp_generator.h
index 90eb7e2..f0585af 100644
--- a/src/compiler/csharp_generator.h
+++ b/src/compiler/csharp_generator.h
@@ -40,7 +40,9 @@
 
 namespace grpc_csharp_generator {
 
-grpc::string GetServices(const grpc::protobuf::FileDescriptor *file);
+grpc::string GetServices(const grpc::protobuf::FileDescriptor *file,
+                         bool generate_client, bool generate_server,
+                         bool internal_access);
 
 }  // namespace grpc_csharp_generator
 
diff --git a/src/compiler/csharp_plugin.cc b/src/compiler/csharp_plugin.cc
index 8b9395f..5350e73 100644
--- a/src/compiler/csharp_plugin.cc
+++ b/src/compiler/csharp_plugin.cc
@@ -48,7 +48,29 @@
                 const grpc::string &parameter,
                 grpc::protobuf::compiler::GeneratorContext *context,
                 grpc::string *error) const {
-    grpc::string code = grpc_csharp_generator::GetServices(file);
+    std::vector<std::pair<grpc::string, grpc::string> > options;
+    grpc::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
+
+    bool generate_client = true;
+    bool generate_server = true;
+    bool internal_access = false;
+    for (size_t i = 0; i < options.size(); i++) {
+      if (options[i].first == "no_client") {
+        generate_client = false;
+      } else if (options[i].first == "no_server") {
+        generate_server = false;
+      } else if (options[i].first == "internal_access") {
+        internal_access = true;
+      } else {
+        *error = "Unknown generator option: " + options[i].first;
+        return false;
+      }
+    }
+
+    grpc::string code = grpc_csharp_generator::GetServices(file,
+                                                           generate_client,
+                                                           generate_server,
+                                                           internal_access);
     if (code.size() == 0) {
       return true;  // don't generate a file if there are no services
     }
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index ff09205..465491e 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -75,11 +75,11 @@
   if (method->server_streaming()) {
     printer->Print(vars,
                    " eventHandler:(void(^)(BOOL done, "
-                   "$response_class$ *response, NSError *error))eventHandler");
+                   "$response_class$ *_Nullable response, NSError *_Nullable error))eventHandler");
   } else {
     printer->Print(vars,
-                   " handler:(void(^)($response_class$ *response, "
-                   "NSError *error))handler");
+                   " handler:(void(^)($response_class$ *_Nullable response, "
+                   "NSError *_Nullable error))handler");
   }
 }
 
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index 1744035..3ccfd5b 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -81,8 +81,12 @@
         declarations += grpc_objective_c_generator::GetHeader(service);
       }
 
+      static const ::grpc::string kNonNullBegin = "\nNS_ASSUME_NONNULL_BEGIN\n\n";
+      static const ::grpc::string kNonNullEnd = "\nNS_ASSUME_NONNULL_END\n";
+
       Write(context, file_name + ".pbrpc.h",
-          imports + '\n' + proto_imports + '\n' + declarations);
+          imports + '\n' + proto_imports + '\n' + kNonNullBegin + 
+          declarations + kNonNullEnd);
     }
 
     {
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index 02c0328..59137e1 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -190,7 +190,7 @@
         "Documentation", doc,
       });
   out->Print("\n");
-  out->Print(dict, "class Beta$Service$Servicer(six.with_metaclass(abc.ABCMeta, object)):\n");
+  out->Print(dict, "class Beta$Service$Servicer(object):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@@ -198,12 +198,11 @@
       auto meth = service->method(i);
       grpc::string arg_name = meth->client_streaming() ?
           "request_iterator" : "request";
-      out->Print("@abc.abstractmethod\n");
       out->Print("def $Method$(self, $ArgName$, context):\n",
                  "Method", meth->name(), "ArgName", arg_name);
       {
         IndentScope raii_method_indent(out);
-        out->Print("raise NotImplementedError()\n");
+        out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n");
       }
     }
   }
@@ -218,7 +217,7 @@
         "Documentation", doc,
       });
   out->Print("\n");
-  out->Print(dict, "class Beta$Service$Stub(six.with_metaclass(abc.ABCMeta, object)):\n");
+  out->Print(dict, "class Beta$Service$Stub(object):\n");
   {
     IndentScope raii_class_indent(out);
     out->Print(dict, "\"\"\"$Documentation$\"\"\"\n");
@@ -227,7 +226,6 @@
       grpc::string arg_name = meth->client_streaming() ?
           "request_iterator" : "request";
       auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name});
-      out->Print("@abc.abstractmethod\n");
       out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n");
       {
         IndentScope raii_method_indent(out);
@@ -450,6 +448,8 @@
   out->Print("import six\n");
   out->Print("from $Package$ import implementations as beta_implementations\n",
              "Package", config.beta_package_root);
+  out->Print("from $Package$ import interfaces as beta_interfaces\n",
+             "Package", config.beta_package_root);
   out->Print("from grpc.framework.common import cardinality\n");
   out->Print("from grpc.framework.interfaces.face import utilities as face_utilities\n");
   return true;
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index abfb3bb..5e278ef 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -134,7 +134,7 @@
 }
 
 static void client_destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_element *elem) {
+                                     grpc_call_element *elem, void *ignored) {
   call_data *d = elem->call_data;
   GPR_ASSERT(d != NULL);
   /* TODO(hongyu): record rpc client stats and census_rpc_end_op here */
@@ -152,7 +152,7 @@
 }
 
 static void server_destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                                     grpc_call_element *elem) {
+                                     grpc_call_element *elem, void *ignored) {
   call_data *d = elem->call_data;
   GPR_ASSERT(d != NULL);
   /* TODO(hongyu): record rpc server stats and census_tracing_end_op here */
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index 8a98a6b..9b5a078 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -415,9 +415,10 @@
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *and_free_memory) {
   grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
+  gpr_free(and_free_memory);
 }
 
 /* Constructor for channel_data */
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index c925c28..3a5af9f 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -644,9 +644,9 @@
                                     bool success) {
   grpc_subchannel_call *c = call;
   GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
-  grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
-  GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call");
-  gpr_free(c);
+  grpc_connected_subchannel *connection = c->connection;
+  grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), c);
+  GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, connection, "subchannel_call");
   GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0);
 }
 
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 01507f5..fcf2abf 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -81,27 +81,25 @@
 
 static const grpc_transport_vtable vtable;
 
-static void lock(grpc_chttp2_transport *t);
-static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
-
 /* forward declarations of various callbacks that we'll build closures around */
 static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
                            bool iomgr_success_ignored);
+static void reading_action(grpc_exec_ctx *exec_ctx, void *t,
+                           bool iomgr_success_ignored);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *t,
+                           bool iomgr_success_ignored);
 
 /** Set a transport level setting, and push it to our peer */
 static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
                          uint32_t value);
 
-/** Endpoint callback to process incoming data */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success);
-
 /** Start disconnection chain */
 static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
 
 /** Perform a transport_op */
-static void perform_stream_op_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
+static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     grpc_chttp2_stream *s, void *transport_op);
 
 /** Cancel a stream: coming from the transport API */
 static void cancel_from_api(grpc_exec_ctx *exec_ctx,
@@ -118,15 +116,19 @@
 /** Add endpoint from this transport to pollset */
 static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
                                   grpc_chttp2_transport *t,
-                                  grpc_pollset *pollset);
+                                  grpc_chttp2_stream *s_ignored, void *pollset);
 static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
                                       grpc_chttp2_transport *t,
-                                      grpc_pollset_set *pollset_set);
+                                      grpc_chttp2_stream *s_ignored,
+                                      void *pollset_set);
 
 /** Start new streams that have been created if we can */
 static void maybe_start_some_streams(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global);
 
+static void finish_global_actions(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t);
+
 static void connectivity_state_set(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
     grpc_connectivity_state state, const char *reason);
@@ -138,7 +140,10 @@
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
     size_t have_already);
-
+static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
+                                                grpc_chttp2_transport *t,
+                                                grpc_chttp2_stream *s,
+                                                void *byte_stream);
 static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
                                 grpc_chttp2_stream_global *stream_global);
 
@@ -150,7 +155,7 @@
                                grpc_chttp2_transport *t) {
   size_t i;
 
-  gpr_mu_lock(&t->mu);
+  gpr_mu_lock(&t->executor.mu);
 
   GPR_ASSERT(t->ep == NULL);
 
@@ -176,8 +181,8 @@
   grpc_chttp2_stream_map_destroy(&t->new_stream_map);
   grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);
 
-  gpr_mu_unlock(&t->mu);
-  gpr_mu_destroy(&t->mu);
+  gpr_mu_unlock(&t->executor.mu);
+  gpr_mu_destroy(&t->executor.mu);
 
   /* callback remaining pings: they're not allowed to call into the transpot,
      and maybe they hold resources that need to be freed */
@@ -238,7 +243,7 @@
   gpr_ref_init(&t->refs, 2);
   /* ref is dropped at transport close() */
   gpr_ref_init(&t->shutdown_ep_refs, 1);
-  gpr_mu_init(&t->mu);
+  gpr_mu_init(&t->executor.mu);
   t->peer_string = grpc_endpoint_get_peer(ep);
   t->endpoint_reading = 1;
   t->global.next_stream_id = is_client ? 1 : 2;
@@ -262,6 +267,8 @@
   gpr_slice_buffer_init(&t->writing.outbuf);
   grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
   grpc_closure_init(&t->writing_action, writing_action, t);
+  grpc_closure_init(&t->reading_action, reading_action, t);
+  grpc_closure_init(&t->parsing_action, parsing_action, t);
 
   gpr_slice_buffer_init(&t->parsing.qbuf);
   grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
@@ -269,7 +276,6 @@
 
   grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
                     &t->writing);
-  grpc_closure_init(&t->recv_data, recv_data, t);
   gpr_slice_buffer_init(&t->read_buffer);
 
   if (is_client) {
@@ -377,14 +383,18 @@
   }
 }
 
-static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-
-  lock(t);
+static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     grpc_chttp2_stream *s_ignored,
+                                     void *arg_ignored) {
   t->destroying = 1;
   drop_connection(exec_ctx, t);
-  unlock(exec_ctx, t);
+}
 
+static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, destroy_transport_locked,
+                                   NULL, 0);
   UNREF_TRANSPORT(exec_ctx, t, "destroy");
 }
 
@@ -404,17 +414,6 @@
   }
 }
 
-static void allow_endpoint_shutdown_unlocked(grpc_exec_ctx *exec_ctx,
-                                             grpc_chttp2_transport *t) {
-  if (gpr_unref(&t->shutdown_ep_refs)) {
-    gpr_mu_lock(&t->mu);
-    if (t->ep) {
-      grpc_endpoint_shutdown(exec_ctx, t->ep);
-    }
-    gpr_mu_unlock(&t->mu);
-  }
-}
-
 static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
                              grpc_chttp2_transport *t) {
   grpc_endpoint_destroy(exec_ctx, t->ep);
@@ -424,7 +423,9 @@
 }
 
 static void close_transport_locked(grpc_exec_ctx *exec_ctx,
-                                   grpc_chttp2_transport *t) {
+                                   grpc_chttp2_transport *t,
+                                   grpc_chttp2_stream *s_ignored,
+                                   void *arg_ignored) {
   if (!t->closed) {
     t->closed = 1;
     connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_FATAL_FAILURE,
@@ -464,6 +465,13 @@
 }
 #endif
 
+static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *t,
+                                      grpc_chttp2_stream *s,
+                                      void *arg_ignored) {
+  grpc_chttp2_register_stream(t, s);
+}
+
 static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                        grpc_stream *gs, grpc_stream_refcount *refcount,
                        const void *server_data) {
@@ -473,6 +481,10 @@
   memset(s, 0, sizeof(*s));
 
   s->refcount = refcount;
+  /* We reserve one 'active stream' that's dropped when the stream is
+     read-closed. The others are for incoming_byte_streams that are actively
+     reading */
+  gpr_ref_init(&s->global.active_streams, 1);
   GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2");
 
   grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]);
@@ -486,10 +498,8 @@
 
   REF_TRANSPORT(t, "stream");
 
-  lock(t);
-  grpc_chttp2_register_stream(t, s);
   if (server_data) {
-    GPR_ASSERT(t->parsing_active);
+    GPR_ASSERT(t->executor.parsing_active);
     s->global.id = (uint32_t)(uintptr_t)server_data;
     s->parsing.id = s->global.id;
     s->global.outgoing_window =
@@ -502,40 +512,42 @@
     grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
     s->global.in_stream_map = 1;
   }
-  unlock(exec_ctx, t);
+
+  grpc_chttp2_run_with_global_lock(exec_ctx, t, s, finish_init_stream_locked,
+                                   NULL, 0);
 
   return 0;
 }
 
-static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
-                           grpc_stream *gs) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
-  int i;
+static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t,
+                                  grpc_chttp2_stream *s, void *arg) {
   grpc_byte_stream *bs;
 
   GPR_TIMER_BEGIN("destroy_stream", 0);
 
-  gpr_mu_lock(&t->mu);
-
   GPR_ASSERT((s->global.write_closed && s->global.read_closed) ||
              s->global.id == 0);
   GPR_ASSERT(!s->global.in_stream_map);
   if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
-    close_transport_locked(exec_ctx, t);
+    close_transport_locked(exec_ctx, t, NULL, NULL);
   }
-  if (!t->parsing_active && s->global.id) {
+  if (!t->executor.parsing_active && s->global.id) {
     GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
                                            s->global.id) == NULL);
   }
 
+  while (
+      (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
+    incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
+  }
+
   grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
                                                                 &s->global);
   grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
+  grpc_chttp2_list_remove_check_read_ops(&t->global, &s->global);
 
-  gpr_mu_unlock(&t->mu);
-
-  for (i = 0; i < STREAM_LIST_COUNT; i++) {
+  for (int i = 0; i < STREAM_LIST_COUNT; i++) {
     if (s->included[i]) {
       gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
               t->global.is_client ? "client" : "server", s->global.id, i);
@@ -543,11 +555,6 @@
     }
   }
 
-  while (
-      (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
-    grpc_byte_stream_destroy(exec_ctx, bs);
-  }
-
   GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
   GPR_ASSERT(s->global.send_message_finished == NULL);
   GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
@@ -566,6 +573,17 @@
   UNREF_TRANSPORT(exec_ctx, t, "stream");
 
   GPR_TIMER_END("destroy_stream", 0);
+
+  gpr_free(arg);
+}
+
+static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
+                           grpc_stream *gs, void *and_free_memory) {
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
+
+  grpc_chttp2_run_with_global_lock(exec_ctx, t, s, destroy_stream_locked,
+                                   and_free_memory, 0);
 }
 
 grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
@@ -594,28 +612,89 @@
  * LOCK MANAGEMENT
  */
 
-/* We take a grpc_chttp2_transport-global lock in response to calls coming in
-   from above,
-   and in response to data being received from below. New data to be written
-   is always queued, as are callbacks to process data. During unlock() we
-   check our todo lists and initiate callbacks and flush writes. */
+static void finish_global_actions(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t) {
+  grpc_chttp2_executor_action_header *hdr;
+  grpc_chttp2_executor_action_header *next;
 
-static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
+  for (;;) {
+    if (!t->executor.writing_active && !t->closed &&
+        grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
+                                           t->executor.parsing_active)) {
+      t->executor.writing_active = 1;
+      REF_TRANSPORT(t, "writing");
+      prevent_endpoint_shutdown(t);
+      grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
+    }
+    check_read_ops(exec_ctx, &t->global);
 
-static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
-  GPR_TIMER_BEGIN("unlock", 0);
-  if (!t->writing_active && !t->closed &&
-      grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing,
-                                         t->parsing_active)) {
-    t->writing_active = 1;
-    REF_TRANSPORT(t, "writing");
-    grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
-    prevent_endpoint_shutdown(t);
+    gpr_mu_lock(&t->executor.mu);
+    if (t->executor.pending_actions != NULL) {
+      hdr = t->executor.pending_actions;
+      t->executor.pending_actions = NULL;
+      gpr_mu_unlock(&t->executor.mu);
+      while (hdr != NULL) {
+        hdr->action(exec_ctx, t, hdr->stream, hdr->arg);
+        next = hdr->next;
+        gpr_free(hdr);
+        UNREF_TRANSPORT(exec_ctx, t, "pending_action");
+        hdr = next;
+      }
+      continue;
+    } else {
+      t->executor.global_active = false;
+    }
+    gpr_mu_unlock(&t->executor.mu);
+    break;
   }
-  check_read_ops(exec_ctx, &t->global);
+}
 
-  gpr_mu_unlock(&t->mu);
-  GPR_TIMER_END("unlock", 0);
+void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *t,
+                                      grpc_chttp2_stream *optional_stream,
+                                      grpc_chttp2_locked_action action,
+                                      void *arg, size_t sizeof_arg) {
+  grpc_chttp2_executor_action_header *hdr;
+
+  REF_TRANSPORT(t, "run_global");
+  gpr_mu_lock(&t->executor.mu);
+
+  for (;;) {
+    if (!t->executor.global_active) {
+      t->executor.global_active = 1;
+      gpr_mu_unlock(&t->executor.mu);
+
+      action(exec_ctx, t, optional_stream, arg);
+
+      finish_global_actions(exec_ctx, t);
+    } else {
+      gpr_mu_unlock(&t->executor.mu);
+
+      hdr = gpr_malloc(sizeof(*hdr) + sizeof_arg);
+      hdr->stream = optional_stream;
+      hdr->action = action;
+      if (sizeof_arg == 0) {
+        hdr->arg = arg;
+      } else {
+        hdr->arg = hdr + 1;
+        memcpy(hdr->arg, arg, sizeof_arg);
+      }
+
+      gpr_mu_lock(&t->executor.mu);
+      if (!t->executor.global_active) {
+        /* global lock was released while allocating memory: release & retry */
+        gpr_free(hdr);
+        continue;
+      }
+      hdr->next = t->executor.pending_actions;
+      t->executor.pending_actions = hdr;
+      REF_TRANSPORT(t, "pending_action");
+      gpr_mu_unlock(&t->executor.mu);
+    }
+    break;
+  }
+
+  UNREF_TRANSPORT(exec_ctx, t, "run_global");
 }
 
 /*******************************************************************************
@@ -645,15 +724,11 @@
   }
 }
 
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing_ptr, bool success) {
-  grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
-  grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
-  grpc_chttp2_stream_global *stream_global;
-
-  GPR_TIMER_BEGIN("grpc_chttp2_terminate_writing", 0);
-
-  lock(t);
+static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_transport *t,
+                                        grpc_chttp2_stream *s_ignored,
+                                        void *a) {
+  bool success = (bool)(uintptr_t)a;
 
   allow_endpoint_shutdown_locked(exec_ctx, t);
 
@@ -663,24 +738,30 @@
 
   grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
 
+  grpc_chttp2_stream_global *stream_global;
   while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
                                                          &stream_global)) {
     fail_pending_writes(exec_ctx, stream_global);
     GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
   }
 
-  /* leave the writing flag up on shutdown to prevent further writes in unlock()
+  /* leave the writing flag up on shutdown to prevent further writes in
+     unlock()
      from starting */
-  t->writing_active = 0;
+  t->executor.writing_active = 0;
   if (t->ep && !t->endpoint_reading) {
     destroy_endpoint(exec_ctx, t);
   }
 
-  unlock(exec_ctx, t);
-
   UNREF_TRANSPORT(exec_ctx, t, "writing");
+}
 
-  GPR_TIMER_END("grpc_chttp2_terminate_writing", 0);
+void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
+                                   void *transport_writing, bool success) {
+  grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
+  grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL,
+                                   terminate_writing_with_lock,
+                                   (void *)(uintptr_t)success, 0);
 }
 
 static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
@@ -806,14 +887,16 @@
 
 static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
 
-static void perform_stream_op_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
-  grpc_closure *on_complete;
-
+static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     grpc_chttp2_stream *s, void *stream_op) {
   GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
 
-  on_complete = op->on_complete;
+  grpc_transport_stream_op *op = stream_op;
+  grpc_chttp2_transport_global *transport_global = &t->global;
+  grpc_chttp2_stream_global *stream_global = &s->global;
+
+  grpc_closure *on_complete = op->on_complete;
   if (on_complete == NULL) {
     on_complete = grpc_closure_create(do_nothing, NULL);
   }
@@ -938,10 +1021,8 @@
                               grpc_stream *gs, grpc_transport_stream_op *op) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
-
-  lock(t);
-  perform_stream_op_locked(exec_ctx, &t->global, &s->global, op);
-  unlock(exec_ctx, t);
+  grpc_chttp2_run_with_global_lock(exec_ctx, t, s, perform_stream_op_locked, op,
+                                   sizeof(*op));
 }
 
 static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
@@ -961,13 +1042,10 @@
   gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
 }
 
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
-                          grpc_chttp2_transport_parsing *transport_parsing,
-                          const uint8_t *opaque_8bytes) {
+static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                            grpc_chttp2_stream *s, void *opaque_8bytes) {
   grpc_chttp2_outstanding_ping *ping;
-  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
   grpc_chttp2_transport_global *transport_global = &t->global;
-  lock(t);
   for (ping = transport_global->pings.next; ping != &transport_global->pings;
        ping = ping->next) {
     if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
@@ -978,13 +1056,31 @@
       break;
     }
   }
-  unlock(exec_ctx, t);
+}
+
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
+                          grpc_chttp2_transport_parsing *transport_parsing,
+                          const uint8_t *opaque_8bytes) {
+  grpc_chttp2_run_with_global_lock(
+      exec_ctx, TRANSPORT_FROM_PARSING(transport_parsing), NULL,
+      ack_ping_locked, (void *)opaque_8bytes, 8);
 }
 
 static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
                                         grpc_chttp2_transport *t,
-                                        grpc_transport_op *op) {
-  bool close_transport = false;
+                                        grpc_chttp2_stream *s_unused,
+                                        void *stream_op) {
+  grpc_transport_op *op = stream_op;
+  bool close_transport = op->disconnect;
+
+  /* If there's a set_accept_stream ensure that we're not parsing
+     to avoid changing things out from underneath */
+  if (t->executor.parsing_active && op->set_accept_stream) {
+    GPR_ASSERT(t->post_parsing_op == NULL);
+    t->post_parsing_op = gpr_malloc(sizeof(*op));
+    memcpy(t->post_parsing_op, op, sizeof(*op));
+    return;
+  }
 
   grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
 
@@ -1010,47 +1106,31 @@
   }
 
   if (op->bind_pollset) {
-    add_to_pollset_locked(exec_ctx, t, op->bind_pollset);
+    add_to_pollset_locked(exec_ctx, t, NULL, op->bind_pollset);
   }
 
   if (op->bind_pollset_set) {
-    add_to_pollset_set_locked(exec_ctx, t, op->bind_pollset_set);
+    add_to_pollset_set_locked(exec_ctx, t, NULL, op->bind_pollset_set);
   }
 
   if (op->send_ping) {
     send_ping_locked(t, op->send_ping);
   }
 
-  if (op->disconnect) {
-    close_transport_locked(exec_ctx, t);
-  }
-
   if (close_transport) {
-    close_transport_locked(exec_ctx, t);
+    close_transport_locked(exec_ctx, t, NULL, NULL);
   }
 }
 
 static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                                  grpc_transport_op *op) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-
-  lock(t);
-
-  /* If there's a set_accept_stream ensure that we're not parsing
-     to avoid changing things out from underneath */
-  if (t->parsing_active && op->set_accept_stream) {
-    GPR_ASSERT(t->post_parsing_op == NULL);
-    t->post_parsing_op = gpr_malloc(sizeof(*op));
-    memcpy(t->post_parsing_op, op, sizeof(*op));
-  } else {
-    perform_transport_op_locked(exec_ctx, t, op);
-  }
-
-  unlock(exec_ctx, t);
+  grpc_chttp2_run_with_global_lock(
+      exec_ctx, t, NULL, perform_transport_op_locked, op, sizeof(*op));
 }
 
 /*******************************************************************************
- * INPUT PROCESSING
+ * INPUT PROCESSING - GENERAL
  */
 
 static void check_read_ops(grpc_exec_ctx *exec_ctx,
@@ -1072,7 +1152,7 @@
       while (stream_global->seen_error &&
              (bs = grpc_chttp2_incoming_frame_queue_pop(
                   &stream_global->incoming_frames)) != NULL) {
-        grpc_byte_stream_destroy(exec_ctx, bs);
+        incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
       }
       if (stream_global->incoming_frames.head != NULL) {
         *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
@@ -1093,9 +1173,9 @@
       while (stream_global->seen_error &&
              (bs = grpc_chttp2_incoming_frame_queue_pop(
                   &stream_global->incoming_frames)) != NULL) {
-        grpc_byte_stream_destroy(exec_ctx, bs);
+        incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
       }
-      if (stream_global->incoming_frames.head == NULL) {
+      if (stream_global->all_incoming_byte_streams_finished) {
         grpc_chttp2_incoming_metadata_buffer_publish(
             &stream_global->received_trailing_metadata,
             stream_global->recv_trailing_metadata);
@@ -1107,6 +1187,15 @@
   }
 }
 
+static void decrement_active_streams_locked(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  if ((stream_global->all_incoming_byte_streams_finished =
+           gpr_unref(&stream_global->active_streams))) {
+    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  }
+}
+
 static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                           uint32_t id) {
   size_t new_stream_count;
@@ -1128,7 +1217,7 @@
   }
 
   if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
-    close_transport_locked(exec_ctx, t);
+    close_transport_locked(exec_ctx, t, NULL, NULL);
   }
   if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
     GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
@@ -1229,10 +1318,11 @@
     stream_global->read_closed = 1;
     stream_global->published_initial_metadata = 1;
     stream_global->published_trailing_metadata = 1;
+    decrement_active_streams_locked(exec_ctx, transport_global, stream_global);
   }
   if (close_writes && !stream_global->write_closed) {
     stream_global->write_closed = 1;
-    if (TRANSPORT_FROM_GLOBAL(transport_global)->writing_active) {
+    if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.writing_active) {
       GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
       grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
                                                       stream_global);
@@ -1242,7 +1332,7 @@
   }
   if (stream_global->read_closed && stream_global->write_closed) {
     if (stream_global->id != 0 &&
-        TRANSPORT_FROM_GLOBAL(transport_global)->parsing_active) {
+        TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) {
       grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
                                                       stream_global);
     } else {
@@ -1374,7 +1464,7 @@
 }
 
 static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
-  close_transport_locked(exec_ctx, t);
+  close_transport_locked(exec_ctx, t, NULL, NULL);
   end_all_the_calls(exec_ctx, t);
 }
 
@@ -1398,102 +1488,136 @@
   }
 }
 
-static void read_error_locked(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_transport *t) {
-  t->endpoint_reading = 0;
-  if (!t->writing_active && t->ep) {
-    destroy_endpoint(exec_ctx, t);
-  }
+/*******************************************************************************
+ * INPUT PROCESSING - PARSING
+ */
+
+static void reading_action_locked(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t,
+                                  grpc_chttp2_stream *s_unused, void *arg);
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success);
+static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_transport *t,
+                                       grpc_chttp2_stream *s_unused, void *arg);
+static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                              grpc_chttp2_stream *s_unused, void *arg);
+
+static void reading_action(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
+  /* Control flow:
+     reading_action_locked ->
+       (parse_unlocked -> post_parse_locked)? ->
+       post_reading_action_locked */
+  grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
+                                   (void *)(uintptr_t)success, 0);
 }
 
-/* tcp read callback */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
-  size_t i;
-  int keep_reading = 0;
-  grpc_chttp2_transport *t = tp;
+static void reading_action_locked(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_transport *t,
+                                  grpc_chttp2_stream *s_unused, void *arg) {
   grpc_chttp2_transport_global *transport_global = &t->global;
   grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
-  grpc_chttp2_stream_global *stream_global;
+  bool success = (bool)(uintptr_t)arg;
 
-  GPR_TIMER_BEGIN("recv_data", 0);
-
-  lock(t);
-  i = 0;
-  GPR_ASSERT(!t->parsing_active);
+  GPR_ASSERT(!t->executor.parsing_active);
   if (!t->closed) {
-    t->parsing_active = 1;
+    t->executor.parsing_active = 1;
     /* merge stream lists */
     grpc_chttp2_stream_map_move_into(&t->new_stream_map,
                                      &t->parsing_stream_map);
     grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
-    gpr_mu_unlock(&t->mu);
-    GPR_TIMER_BEGIN("recv_data.parse", 0);
-    for (; i < t->read_buffer.count &&
-           grpc_chttp2_perform_read(exec_ctx, transport_parsing,
-                                    t->read_buffer.slices[i]);
-         i++)
-      ;
-    GPR_TIMER_END("recv_data.parse", 0);
-    gpr_mu_lock(&t->mu);
-    /* copy parsing qbuf to global qbuf */
-    gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
-    if (i != t->read_buffer.count) {
-      unlock(exec_ctx, t);
-      lock(t);
-      drop_connection(exec_ctx, t);
-    }
-    /* merge stream lists */
-    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
-                                     &t->parsing_stream_map);
-    transport_global->concurrent_stream_count =
-        (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
-    if (transport_parsing->initial_window_update != 0) {
-      grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
-                                      update_global_window, t);
-      transport_parsing->initial_window_update = 0;
-    }
-    /* handle higher level things */
-    grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
-    t->parsing_active = 0;
-    /* handle delayed transport ops (if there is one) */
-    if (t->post_parsing_op) {
-      grpc_transport_op *op = t->post_parsing_op;
-      t->post_parsing_op = NULL;
-      perform_transport_op_locked(exec_ctx, t, op);
-      gpr_free(op);
-    }
-    /* if a stream is in the stream map, and gets cancelled, we need to ensure
-     * we are not parsing before continuing the cancellation to keep things in
-     * a sane state */
-    while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
-                                                           &stream_global)) {
-      GPR_ASSERT(stream_global->in_stream_map);
-      GPR_ASSERT(stream_global->write_closed);
-      GPR_ASSERT(stream_global->read_closed);
-      remove_stream(exec_ctx, t, stream_global->id);
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
-    }
+    grpc_exec_ctx_enqueue(exec_ctx, &t->parsing_action, success, NULL);
+  } else {
+    post_reading_action_locked(exec_ctx, t, s_unused, arg);
   }
-  if (!success || i != t->read_buffer.count || t->closed) {
+}
+
+static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
+  grpc_chttp2_transport *t = arg;
+  GPR_TIMER_BEGIN("reading_action.parse", 0);
+  size_t i = 0;
+  for (; i < t->read_buffer.count &&
+         grpc_chttp2_perform_read(exec_ctx, &t->parsing,
+                                  t->read_buffer.slices[i]);
+       i++)
+    ;
+  if (i != t->read_buffer.count) {
+    success = false;
+  }
+  GPR_TIMER_END("reading_action.parse", 0);
+  grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked,
+                                   (void *)(uintptr_t)success, 0);
+}
+
+static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                              grpc_chttp2_stream *s_unused, void *arg) {
+  grpc_chttp2_transport_global *transport_global = &t->global;
+  grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
+  /* copy parsing qbuf to global qbuf */
+  gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
+  /* merge stream lists */
+  grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map);
+  transport_global->concurrent_stream_count =
+      (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
+  if (transport_parsing->initial_window_update != 0) {
+    grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
+                                    update_global_window, t);
+    transport_parsing->initial_window_update = 0;
+  }
+  /* handle higher level things */
+  grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
+  t->executor.parsing_active = 0;
+  /* handle delayed transport ops (if there is one) */
+  if (t->post_parsing_op) {
+    grpc_transport_op *op = t->post_parsing_op;
+    t->post_parsing_op = NULL;
+    perform_transport_op_locked(exec_ctx, t, NULL, op);
+    gpr_free(op);
+  }
+  /* if a stream is in the stream map, and gets cancelled, we need to
+   * ensure we are not parsing before continuing the cancellation to keep
+   * things in a sane state */
+  grpc_chttp2_stream_global *stream_global;
+  while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
+                                                         &stream_global)) {
+    GPR_ASSERT(stream_global->in_stream_map);
+    GPR_ASSERT(stream_global->write_closed);
+    GPR_ASSERT(stream_global->read_closed);
+    remove_stream(exec_ctx, t, stream_global->id);
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
+  }
+
+  post_reading_action_locked(exec_ctx, t, s_unused, arg);
+}
+
+static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_transport *t,
+                                       grpc_chttp2_stream *s_unused,
+                                       void *arg) {
+  bool success = (bool)(uintptr_t)arg;
+  bool keep_reading = false;
+  if (!success || t->closed) {
     drop_connection(exec_ctx, t);
-    read_error_locked(exec_ctx, t);
+    t->endpoint_reading = 0;
+    if (!t->executor.writing_active && t->ep) {
+      grpc_endpoint_destroy(exec_ctx, t->ep);
+      t->ep = NULL;
+      /* safe as we still have a ref for read */
+      UNREF_TRANSPORT(exec_ctx, t, "disconnect");
+    }
   } else if (!t->closed) {
-    keep_reading = 1;
+    keep_reading = true;
     REF_TRANSPORT(t, "keep_reading");
     prevent_endpoint_shutdown(t);
   }
   gpr_slice_buffer_reset_and_unref(&t->read_buffer);
-  unlock(exec_ctx, t);
 
   if (keep_reading) {
-    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->recv_data);
-    allow_endpoint_shutdown_unlocked(exec_ctx, t);
+    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->reading_action);
+    allow_endpoint_shutdown_locked(exec_ctx, t);
     UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
   } else {
-    UNREF_TRANSPORT(exec_ctx, t, "recv_data");
+    UNREF_TRANSPORT(exec_ctx, t, "reading_action");
   }
-
-  GPR_TIMER_END("recv_data", 0);
 }
 
 /*******************************************************************************
@@ -1517,7 +1641,7 @@
 
 static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
                                   grpc_chttp2_transport *t,
-                                  grpc_pollset *pollset) {
+                                  grpc_chttp2_stream *s_unused, void *pollset) {
   if (t->ep) {
     grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
   }
@@ -1525,7 +1649,8 @@
 
 static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
                                       grpc_chttp2_transport *t,
-                                      grpc_pollset_set *pollset_set) {
+                                      grpc_chttp2_stream *s_unused,
+                                      void *pollset_set) {
   if (t->ep) {
     grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
   }
@@ -1533,16 +1658,24 @@
 
 static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                         grpc_stream *gs, grpc_pollset *pollset) {
-  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  lock(t);
-  add_to_pollset_locked(exec_ctx, t, pollset);
-  unlock(exec_ctx, t);
+  /* TODO(ctiller): keep pollset alive */
+  grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
+                                   (grpc_chttp2_stream *)gs,
+                                   add_to_pollset_locked, pollset, 0);
 }
 
 /*******************************************************************************
  * BYTE STREAM
  */
 
+static void incoming_byte_stream_unref(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_incoming_byte_stream *bs) {
+  if (gpr_unref(&bs->refs)) {
+    gpr_slice_buffer_destroy(&bs->slices);
+    gpr_free(bs);
+  }
+}
+
 static void incoming_byte_stream_update_flow_control(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
@@ -1583,87 +1716,146 @@
   }
 }
 
+typedef struct {
+  grpc_chttp2_incoming_byte_stream *byte_stream;
+  gpr_slice *slice;
+  size_t max_size_hint;
+  grpc_closure *on_complete;
+} incoming_byte_stream_next_arg;
+
+static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
+                                             grpc_chttp2_transport *t,
+                                             grpc_chttp2_stream *s,
+                                             void *argp) {
+  incoming_byte_stream_next_arg *arg = argp;
+  grpc_chttp2_incoming_byte_stream *bs =
+      (grpc_chttp2_incoming_byte_stream *)arg->byte_stream;
+  grpc_chttp2_transport_global *transport_global = &bs->transport->global;
+  grpc_chttp2_stream_global *stream_global = &bs->stream->global;
+
+  if (bs->is_tail) {
+    incoming_byte_stream_update_flow_control(
+        transport_global, stream_global, arg->max_size_hint, bs->slices.length);
+  }
+  if (bs->slices.count > 0) {
+    *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
+    grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, true, NULL);
+  } else if (bs->failed) {
+    grpc_exec_ctx_enqueue(exec_ctx, arg->on_complete, false, NULL);
+  } else {
+    bs->on_next = arg->on_complete;
+    bs->next = arg->slice;
+  }
+  incoming_byte_stream_unref(exec_ctx, bs);
+}
+
 static int incoming_byte_stream_next(grpc_exec_ctx *exec_ctx,
                                      grpc_byte_stream *byte_stream,
                                      gpr_slice *slice, size_t max_size_hint,
                                      grpc_closure *on_complete) {
   grpc_chttp2_incoming_byte_stream *bs =
       (grpc_chttp2_incoming_byte_stream *)byte_stream;
-  grpc_chttp2_transport_global *transport_global = &bs->transport->global;
-  grpc_chttp2_stream_global *stream_global = &bs->stream->global;
-
-  lock(bs->transport);
-  if (bs->is_tail) {
-    incoming_byte_stream_update_flow_control(transport_global, stream_global,
-                                             max_size_hint, bs->slices.length);
-  }
-  if (bs->slices.count > 0) {
-    *slice = gpr_slice_buffer_take_first(&bs->slices);
-    unlock(exec_ctx, bs->transport);
-    return 1;
-  } else if (bs->failed) {
-    grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL);
-    unlock(exec_ctx, bs->transport);
-    return 0;
-  } else {
-    bs->on_next = on_complete;
-    bs->next = slice;
-    unlock(exec_ctx, bs->transport);
-    return 0;
-  }
+  incoming_byte_stream_next_arg arg = {bs, slice, max_size_hint, on_complete};
+  gpr_ref(&bs->refs);
+  grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+                                   incoming_byte_stream_next_locked, &arg,
+                                   sizeof(arg));
+  return 0;
 }
 
-static void incoming_byte_stream_unref(grpc_chttp2_incoming_byte_stream *bs) {
-  if (gpr_unref(&bs->refs)) {
-    gpr_slice_buffer_destroy(&bs->slices);
-    gpr_free(bs);
-  }
+static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
+                                         grpc_byte_stream *byte_stream);
+
+static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
+                                                grpc_chttp2_transport *t,
+                                                grpc_chttp2_stream *s,
+                                                void *byte_stream) {
+  grpc_chttp2_incoming_byte_stream *bs = byte_stream;
+  GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy);
+  decrement_active_streams_locked(exec_ctx, &bs->transport->global,
+                                  &bs->stream->global);
+  incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
                                          grpc_byte_stream *byte_stream) {
-  incoming_byte_stream_unref((grpc_chttp2_incoming_byte_stream *)byte_stream);
+  grpc_chttp2_incoming_byte_stream *bs =
+      (grpc_chttp2_incoming_byte_stream *)byte_stream;
+  grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+                                   incoming_byte_stream_destroy_locked, bs, 0);
+}
+
+typedef struct {
+  grpc_chttp2_incoming_byte_stream *byte_stream;
+  gpr_slice slice;
+} incoming_byte_stream_push_arg;
+
+static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
+                                             grpc_chttp2_transport *t,
+                                             grpc_chttp2_stream *s,
+                                             void *argp) {
+  incoming_byte_stream_push_arg *arg = argp;
+  grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
+  if (bs->on_next != NULL) {
+    *bs->next = arg->slice;
+    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
+    bs->on_next = NULL;
+  } else {
+    gpr_slice_buffer_add(&bs->slices, arg->slice);
+  }
+  incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
                                            grpc_chttp2_incoming_byte_stream *bs,
                                            gpr_slice slice) {
-  gpr_mu_lock(&bs->transport->mu);
-  if (bs->on_next != NULL) {
-    *bs->next = slice;
-    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
-    bs->on_next = NULL;
-  } else {
-    gpr_slice_buffer_add(&bs->slices, slice);
-  }
-  gpr_mu_unlock(&bs->transport->mu);
+  incoming_byte_stream_push_arg arg = {bs, slice};
+  gpr_ref(&bs->refs);
+  grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+                                   incoming_byte_stream_push_locked, &arg,
+                                   sizeof(arg));
+}
+
+static void incoming_byte_stream_finished_failed_locked(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+    void *argp) {
+  grpc_chttp2_incoming_byte_stream *bs = argp;
+  grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
+  bs->on_next = NULL;
+  bs->failed = 1;
+  incoming_byte_stream_unref(exec_ctx, bs);
+}
+
+static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
+                                                    grpc_chttp2_transport *t,
+                                                    grpc_chttp2_stream *s,
+                                                    void *argp) {
+  grpc_chttp2_incoming_byte_stream *bs = argp;
+  incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 void grpc_chttp2_incoming_byte_stream_finished(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs, int success,
     int from_parsing_thread) {
-  if (!success) {
-    if (from_parsing_thread) {
-      gpr_mu_lock(&bs->transport->mu);
-    }
-    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
-    bs->on_next = NULL;
-    bs->failed = 1;
-    if (from_parsing_thread) {
-      gpr_mu_unlock(&bs->transport->mu);
+  if (from_parsing_thread) {
+    if (success) {
+      grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
+                                       incoming_byte_stream_finished_ok_locked,
+                                       bs, 0);
+    } else {
+      incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
+                                              bs->stream, bs);
     }
   } else {
-#ifndef NDEBUG
-    if (from_parsing_thread) {
-      gpr_mu_lock(&bs->transport->mu);
+    if (success) {
+      grpc_chttp2_run_with_global_lock(
+          exec_ctx, bs->transport, bs->stream,
+          incoming_byte_stream_finished_failed_locked, bs, 0);
+    } else {
+      incoming_byte_stream_finished_failed_locked(exec_ctx, bs->transport,
+                                                  bs->stream, bs);
     }
-    GPR_ASSERT(bs->on_next == NULL);
-    if (from_parsing_thread) {
-      gpr_mu_unlock(&bs->transport->mu);
-    }
-#endif
   }
-  incoming_byte_stream_unref(bs);
 }
 
 grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
@@ -1680,6 +1872,7 @@
   incoming_byte_stream->next_message = NULL;
   incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing);
   incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing);
+  gpr_ref(&incoming_byte_stream->stream->global.active_streams);
   gpr_slice_buffer_init(&incoming_byte_stream->slices);
   incoming_byte_stream->on_next = NULL;
   incoming_byte_stream->is_tail = 1;
@@ -1810,7 +2003,7 @@
                                          grpc_transport *transport,
                                          gpr_slice *slices, size_t nslices) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
-  REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
+  REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
   gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
-  recv_data(exec_ctx, t, 1);
+  reading_action(exec_ctx, t, 1);
 }
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 98cd38a..7a80846 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -291,27 +291,44 @@
   int64_t outgoing_window;
 };
 
+typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s, void *arg);
+
+typedef struct grpc_chttp2_executor_action_header {
+  grpc_chttp2_stream *stream;
+  grpc_chttp2_locked_action action;
+  struct grpc_chttp2_executor_action_header *next;
+  void *arg;
+} grpc_chttp2_executor_action_header;
+
 struct grpc_chttp2_transport {
   grpc_transport base; /* must be first */
-  grpc_endpoint *ep;
   gpr_refcount refs;
+  grpc_endpoint *ep;
   char *peer_string;
 
   /** when this drops to zero it's safe to shutdown the endpoint */
   gpr_refcount shutdown_ep_refs;
 
-  gpr_mu mu;
+  struct {
+    gpr_mu mu;
+
+    /** is a thread currently in the global lock */
+    bool global_active;
+    /** is a thread currently writing */
+    bool writing_active;
+    /** is a thread currently parsing */
+    bool parsing_active;
+
+    grpc_chttp2_executor_action_header *pending_actions;
+  } executor;
 
   /** is the transport destroying itself? */
   uint8_t destroying;
   /** has the upper layer closed the transport? */
   uint8_t closed;
 
-  /** is a thread currently writing */
-  uint8_t writing_active;
-  /** is a thread currently parsing */
-  uint8_t parsing_active;
-
   /** is there a read request to the endpoint outstanding? */
   uint8_t endpoint_reading;
 
@@ -338,8 +355,10 @@
 
   /** closure to execute writing */
   grpc_closure writing_action;
-  /** closure to finish reading from the endpoint */
-  grpc_closure recv_data;
+  /** closure to start reading from the endpoint */
+  grpc_closure reading_action;
+  /** closure to actually do parsing */
+  grpc_closure parsing_action;
 
   /** incoming read bytes */
   gpr_slice_buffer read_buffer;
@@ -397,21 +416,26 @@
   grpc_transport_stream_stats *collecting_stats;
   grpc_transport_stream_stats stats;
 
+  /** number of streams that are currently being read */
+  gpr_refcount active_streams;
+
   /** when the application requests writes be closed, the write_closed is
       'queued'; when the close is flow controlled into the send path, we are
       'sending' it; when the write has been performed it is 'sent' */
-  uint8_t write_closed;
+  bool write_closed;
   /** is this stream reading half-closed (boolean) */
-  uint8_t read_closed;
+  bool read_closed;
+  /** are all published incoming byte streams closed */
+  bool all_incoming_byte_streams_finished;
   /** is this stream in the stream map? (boolean) */
-  uint8_t in_stream_map;
+  bool in_stream_map;
   /** has this stream seen an error? if 1, then pending incoming frames
       can be thrown away */
-  uint8_t seen_error;
+  bool seen_error;
 
-  uint8_t published_initial_metadata;
-  uint8_t published_trailing_metadata;
-  uint8_t faked_trailing_metadata;
+  bool published_initial_metadata;
+  bool published_trailing_metadata;
+  bool faked_trailing_metadata;
 
   grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
   grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
@@ -570,6 +594,9 @@
 void grpc_chttp2_list_add_check_read_ops(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global *stream_global);
+bool grpc_chttp2_list_remove_check_read_ops(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global);
 int grpc_chttp2_list_pop_check_read_ops(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global **stream_global);
@@ -645,6 +672,12 @@
                                        grpc_chttp2_stream_global *stream_global,
                                        grpc_closure **pclosure, int success);
 
+void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *transport,
+                                      grpc_chttp2_stream *optional_stream,
+                                      grpc_chttp2_locked_action action,
+                                      void *arg, size_t sizeof_arg);
+
 #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
 #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
   (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c
index e5b35aa..8f3ab00 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.c
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.c
@@ -305,6 +305,14 @@
                   GRPC_CHTTP2_LIST_CHECK_READ_OPS);
 }
 
+bool grpc_chttp2_list_remove_check_read_ops(
+    grpc_chttp2_transport_global *transport_global,
+    grpc_chttp2_stream_global *stream_global) {
+  return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
+                                  STREAM_FROM_GLOBAL(stream_global),
+                                  GRPC_CHTTP2_LIST_CHECK_READ_OPS);
+}
+
 int grpc_chttp2_list_pop_check_read_ops(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global **stream_global) {
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index e36066d..ad182d1 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -213,14 +213,16 @@
                                         grpc_call_element *elem,
                                         grpc_pollset *pollset) {}
 
-void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack) {
+void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
+                             void *and_free_memory) {
   grpc_call_element *elems = CALL_ELEMS_FROM_STACK(stack);
   size_t count = stack->count;
   size_t i;
 
   /* destroy per-filter data */
   for (i = 0; i < count; i++) {
-    elems[i].filter->destroy_call_elem(exec_ctx, &elems[i]);
+    elems[i].filter->destroy_call_elem(exec_ctx, &elems[i],
+                                       i == count - 1 ? and_free_memory : NULL);
   }
 }
 
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 9e3a25a..36c17cb 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -104,8 +104,12 @@
   void (*set_pollset)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
                       grpc_pollset *pollset);
   /* Destroy per call data.
-     The filter does not need to do any chaining */
-  void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+     The filter does not need to do any chaining.
+     The bottom filter of a stack will be passed a non-NULL pointer to
+     \a and_free_memory that should be passed to gpr_free when destruction
+     is complete. */
+  void (*destroy_call_elem)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                            void *and_free_memory);
 
   /* sizeof(per channel data) */
   size_t sizeof_channel_data;
@@ -223,7 +227,8 @@
 #endif
 
 /* Destroy a call stack */
-void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack);
+void grpc_call_stack_destroy(grpc_exec_ctx *exec_ctx, grpc_call_stack *stack,
+                             void *and_free_memory);
 
 /* Ignore set pollset - used by filters to implement the set_pollset method
    if they don't care about pollsets at all. Does nothing. */
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 3d42d0e..bac0811 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -246,8 +246,8 @@
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   gpr_slice_buffer_destroy(&calld->slices);
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index c1debab..68a3a7d 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -102,12 +102,13 @@
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *and_free_memory) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   grpc_transport_destroy_stream(exec_ctx, chand->transport,
-                                TRANSPORT_STREAM_FROM_CALL_DATA(calld));
+                                TRANSPORT_STREAM_FROM_CALL_DATA(calld),
+                                and_free_memory);
 }
 
 /* Constructor for channel_data */
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 211f537..516e708 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -155,8 +155,8 @@
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {}
 
 static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
   unsigned i;
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index 59dded6..ba86541 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -225,8 +225,8 @@
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {}
 
 /* Constructor for channel_data */
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index 8c6ec90..1fa02e1 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -44,7 +44,6 @@
 static const grpc_event_engine_vtable *g_event_engine;
 
 grpc_poll_function_type grpc_poll_function = poll;
-grpc_wakeup_fd grpc_global_wakeup_fd;
 
 void grpc_event_engine_init(void) {
   if ((g_event_engine = grpc_init_poll_and_epoll_posix())) {
diff --git a/src/core/lib/iomgr/iomgr.c b/src/core/lib/iomgr/iomgr.c
index 1466639..60cef8b 100644
--- a/src/core/lib/iomgr/iomgr.c
+++ b/src/core/lib/iomgr/iomgr.c
@@ -166,8 +166,10 @@
   if (env == NULL) return false;
   static const char *truthy[] = {"yes",  "Yes",  "YES", "true",
                                  "True", "TRUE", "1"};
+  bool should_we = false;
   for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
-    if (0 == strcmp(env, truthy[i])) return true;
+    if (0 == strcmp(env, truthy[i])) should_we = true;
   }
-  return false;
+  gpr_free(env);
+  return should_we;
 }
diff --git a/src/core/lib/security/client_auth_filter.c b/src/core/lib/security/client_auth_filter.c
index 943b1da..8b58cb8 100644
--- a/src/core/lib/security/client_auth_filter.c
+++ b/src/core/lib/security/client_auth_filter.c
@@ -277,8 +277,8 @@
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {
   call_data *calld = elem->call_data;
   grpc_call_credentials_unref(calld->creds);
   if (calld->host != NULL) {
diff --git a/src/core/lib/security/server_auth_filter.c b/src/core/lib/security/server_auth_filter.c
index 7844dc8..3320497 100644
--- a/src/core/lib/security/server_auth_filter.c
+++ b/src/core/lib/security/server_auth_filter.c
@@ -224,8 +224,8 @@
                         grpc_pollset *pollset) {}
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {}
 
 /* Constructor for channel_data */
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index fa12b6e..9b2b94e 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -373,8 +373,6 @@
   if (c->receiving_stream != NULL) {
     grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
   }
-  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c));
-  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->channel, "call");
   gpr_mu_destroy(&c->mu);
   for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
     if (c->status[i].details) {
@@ -392,7 +390,9 @@
   if (c->cq) {
     GRPC_CQ_INTERNAL_UNREF(c->cq, "bind");
   }
-  gpr_free(c);
+  grpc_channel *channel = c->channel;
+  grpc_call_stack_destroy(exec_ctx, CALL_STACK_FROM_CALL(c), c);
+  GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, channel, "call");
   GPR_TIMER_END("destroy_call", 0);
 }
 
@@ -1517,3 +1517,39 @@
   gpr_mu_unlock(&call->mu);
   return grpc_compression_algorithm_for_level(level, accepted_encodings);
 }
+
+const char *grpc_call_error_to_string(grpc_call_error error) {
+  switch (error) {
+    case GRPC_CALL_ERROR:
+      return "GRPC_CALL_ERROR";
+    case GRPC_CALL_ERROR_ALREADY_ACCEPTED:
+      return "GRPC_CALL_ERROR_ALREADY_ACCEPTED";
+    case GRPC_CALL_ERROR_ALREADY_FINISHED:
+      return "GRPC_CALL_ERROR_ALREADY_FINISHED";
+    case GRPC_CALL_ERROR_ALREADY_INVOKED:
+      return "GRPC_CALL_ERROR_ALREADY_INVOKED";
+    case GRPC_CALL_ERROR_BATCH_TOO_BIG:
+      return "GRPC_CALL_ERROR_BATCH_TOO_BIG";
+    case GRPC_CALL_ERROR_INVALID_FLAGS:
+      return "GRPC_CALL_ERROR_INVALID_FLAGS";
+    case GRPC_CALL_ERROR_INVALID_MESSAGE:
+      return "GRPC_CALL_ERROR_INVALID_MESSAGE";
+    case GRPC_CALL_ERROR_INVALID_METADATA:
+      return "GRPC_CALL_ERROR_INVALID_METADATA";
+    case GRPC_CALL_ERROR_NOT_INVOKED:
+      return "GRPC_CALL_ERROR_NOT_INVOKED";
+    case GRPC_CALL_ERROR_NOT_ON_CLIENT:
+      return "GRPC_CALL_ERROR_NOT_ON_CLIENT";
+    case GRPC_CALL_ERROR_NOT_ON_SERVER:
+      return "GRPC_CALL_ERROR_NOT_ON_SERVER";
+    case GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE:
+      return "GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE";
+    case GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH:
+      return "GRPC_CALL_ERROR_PAYLOAD_TYPE_MISMATCH";
+    case GRPC_CALL_ERROR_TOO_MANY_OPERATIONS:
+      return "GRPC_CALL_ERROR_TOO_MANY_OPERATIONS";
+    case GRPC_CALL_OK:
+      return "GRPC_CALL_OK";
+  }
+  GPR_UNREACHABLE_CODE(return "GRPC_CALL_ERROR_UNKNOW");
+}
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index d5eb242..ae78f8f 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -230,6 +230,10 @@
 #endif
 
   GPR_TIMER_BEGIN("grpc_cq_end_op", 0);
+  GRPC_API_TRACE(
+      "grpc_cq_end_op(exec_ctx=%p, cc=%p, tag=%p, success=%d, done=%p, "
+      "done_arg=%p, storage=%p)",
+      7, (exec_ctx, cc, tag, success, done, done_arg, storage));
 
   storage->tag = tag;
   storage->done = done;
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 03f379a..d7ee122 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -167,7 +167,6 @@
     grpc_security_pre_init();
     grpc_iomgr_init();
     grpc_executor_init();
-    grpc_tracer_init("GRPC_TRACE");
     gpr_timers_global_init();
     grpc_cq_global_init();
     for (i = 0; i < g_number_of_plugins; i++) {
@@ -179,6 +178,7 @@
      * at the appropriate time */
     grpc_register_security_filters();
     register_builtin_channel_init();
+    grpc_tracer_init("GRPC_TRACE");
     /* no more changes to channel init pipelines */
     grpc_channel_init_finalize();
   }
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 80bd95d..f50ec54 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -107,8 +107,10 @@
 static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
                            grpc_call_element_args *args) {}
 
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *and_free_memory) {
+  gpr_free(and_free_memory);
+}
 
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
                               grpc_channel_element *elem,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 0a84d8e..c9b458f 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -820,8 +820,8 @@
   server_ref(chand->server);
 }
 
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
 
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 53c634a..e6d524a 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -133,8 +133,9 @@
 
 void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
                                    grpc_transport *transport,
-                                   grpc_stream *stream) {
-  transport->vtable->destroy_stream(exec_ctx, transport, stream);
+                                   grpc_stream *stream, void *and_free_memory) {
+  transport->vtable->destroy_stream(exec_ctx, transport, stream,
+                                    and_free_memory);
 }
 
 char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 1eb4463..482a9d1 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -98,6 +98,11 @@
 /* Transport stream op: a set of operations to perform on a transport
    against a single stream */
 typedef struct grpc_transport_stream_op {
+  /** Should be enqueued when all requested operations (excluding recv_message
+      and recv_initial_metadata which have their own closures) in a given batch
+      have been completed. */
+  grpc_closure *on_complete;
+
   /** Send initial metadata to the peer, from the provided metadata batch.
       idempotent_request MUST be set if this is non-null */
   grpc_metadata_batch *send_initial_metadata;
@@ -129,11 +134,6 @@
   /** Collect any stats into provided buffer, zero internal stat counters */
   grpc_transport_stream_stats *collect_stats;
 
-  /** Should be enqueued when all requested operations (excluding recv_message
-      and recv_initial_metadata which have their own closures) in a given batch
-      have been completed. */
-  grpc_closure *on_complete;
-
   /** If != GRPC_STATUS_OK, cancel this stream */
   grpc_status_code cancel_with_status;
 
@@ -213,7 +213,7 @@
                  caller, but any child memory must be cleaned up) */
 void grpc_transport_destroy_stream(grpc_exec_ctx *exec_ctx,
                                    grpc_transport *transport,
-                                   grpc_stream *stream);
+                                   grpc_stream *stream, void *and_free_memory);
 
 void grpc_transport_stream_op_finish_with_failure(grpc_exec_ctx *exec_ctx,
                                                   grpc_transport_stream_op *op);
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 2ff6707..956155e 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -63,7 +63,7 @@
 
   /* implementation of grpc_transport_destroy_stream */
   void (*destroy_stream)(grpc_exec_ctx *exec_ctx, grpc_transport *self,
-                         grpc_stream *stream);
+                         grpc_stream *stream, void *and_free_memory);
 
   /* implementation of grpc_transport_destroy */
   void (*destroy)(grpc_exec_ctx *exec_ctx, grpc_transport *self);
diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs
index 1a6482d..2d3034d 100644
--- a/src/csharp/Grpc.Examples/MathGrpc.cs
+++ b/src/csharp/Grpc.Examples/MathGrpc.cs
@@ -1,5 +1,35 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
 // source: math.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
 #region Designer generated code
 
 using System;
@@ -45,56 +75,140 @@
         __Marshaller_Num,
         __Marshaller_Num);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Math.MathReflection.Descriptor.Services[0]; }
     }
 
-    // client interface
+    /// <summary>Client for Math</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IMathClient
     {
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options);
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options);
+      /// <summary>
+      ///  DivMany accepts an arbitrary number of division args from the client stream
+      ///  and sends back the results in the reply stream.  The stream continues until
+      ///  the client closes its end; the server does the same after sending all the
+      ///  replies.  The stream ends immediately if either end aborts.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  DivMany accepts an arbitrary number of division args from the client stream
+      ///  and sends back the results in the reply stream.  The stream continues until
+      ///  the client closes its end; the server does the same after sending all the
+      ///  replies.  The stream ends immediately if either end aborts.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options);
+      /// <summary>
+      ///  Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      ///  generates up to limit numbers; otherwise it continues until the call is
+      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </summary>
       AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      ///  generates up to limit numbers; otherwise it continues until the call is
+      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </summary>
       AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options);
+      /// <summary>
+      ///  Sum sums a stream of numbers, returning the final result once the stream
+      ///  is closed.
+      /// </summary>
       AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Sum sums a stream of numbers, returning the final result once the stream
+      ///  is closed.
+      /// </summary>
       AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of Math</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IMath
     {
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context);
+      /// <summary>
+      ///  DivMany accepts an arbitrary number of division args from the client stream
+      ///  and sends back the results in the reply stream.  The stream continues until
+      ///  the client closes its end; the server does the same after sending all the
+      ///  replies.  The stream ends immediately if either end aborts.
+      /// </summary>
       Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      ///  generates up to limit numbers; otherwise it continues until the call is
+      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </summary>
       Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  Sum sums a stream of numbers, returning the final result once the stream
+      ///  is closed.
+      /// </summary>
       Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of Math</summary>
     public abstract class MathBase
     {
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       public virtual Task<global::Math.DivReply> Div(global::Math.DivArgs request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  DivMany accepts an arbitrary number of division args from the client stream
+      ///  and sends back the results in the reply stream.  The stream continues until
+      ///  the client closes its end; the server does the same after sending all the
+      ///  replies.  The stream ends immediately if either end aborts.
+      /// </summary>
       public virtual Task DivMany(IAsyncStreamReader<global::Math.DivArgs> requestStream, IServerStreamWriter<global::Math.DivReply> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      ///  generates up to limit numbers; otherwise it continues until the call is
+      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </summary>
       public virtual Task Fib(global::Math.FibArgs request, IServerStreamWriter<global::Math.Num> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  Sum sums a stream of numbers, returning the final result once the stream
+      ///  is closed.
+      /// </summary>
       public virtual Task<global::Math.Num> Sum(IAsyncStreamReader<global::Math.Num> requestStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -102,7 +216,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for Math</summary>
     #pragma warning disable 0618
     public class MathClient : ClientBase<MathClient>, IMathClient
     #pragma warning restore 0618
@@ -122,42 +236,88 @@
       {
       }
 
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       public virtual global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return Div(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       public virtual global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_Div, null, options, request);
       }
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return DivAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Div divides args.dividend by args.divisor and returns the quotient and
+      ///  remainder.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Math.DivReply> DivAsync(global::Math.DivArgs request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_Div, null, options, request);
       }
+      /// <summary>
+      ///  DivMany accepts an arbitrary number of division args from the client stream
+      ///  and sends back the results in the reply stream.  The stream continues until
+      ///  the client closes its end; the server does the same after sending all the
+      ///  replies.  The stream ends immediately if either end aborts.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return DivMany(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  DivMany accepts an arbitrary number of division args from the client stream
+      ///  and sends back the results in the reply stream.  The stream continues until
+      ///  the client closes its end; the server does the same after sending all the
+      ///  replies.  The stream ends immediately if either end aborts.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Math.DivArgs, global::Math.DivReply> DivMany(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_DivMany, null, options);
       }
+      /// <summary>
+      ///  Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      ///  generates up to limit numbers; otherwise it continues until the call is
+      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </summary>
       public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return Fib(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Fib generates numbers in the Fibonacci sequence.  If args.limit > 0, Fib
+      ///  generates up to limit numbers; otherwise it continues until the call is
+      ///  canceled.  Unlike Fib above, Fib has no final FibReply.
+      /// </summary>
       public virtual AsyncServerStreamingCall<global::Math.Num> Fib(global::Math.FibArgs request, CallOptions options)
       {
         return CallInvoker.AsyncServerStreamingCall(__Method_Fib, null, options, request);
       }
+      /// <summary>
+      ///  Sum sums a stream of numbers, returning the final result once the stream
+      ///  is closed.
+      /// </summary>
       public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return Sum(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Sum sums a stream of numbers, returning the final result once the stream
+      ///  is closed.
+      /// </summary>
       public virtual AsyncClientStreamingCall<global::Math.Num, global::Math.Num> Sum(CallOptions options)
       {
         return CallInvoker.AsyncClientStreamingCall(__Method_Sum, null, options);
@@ -168,7 +328,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for Math</summary>
+    public static MathClient NewClient(Channel channel)
+    {
+      return new MathClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IMath serviceImpl)
     #pragma warning restore 0618
@@ -180,7 +346,7 @@
           .AddMethod(__Method_Sum, serviceImpl.Sum).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(MathBase serviceImpl)
     #pragma warning restore 0618
@@ -192,12 +358,6 @@
           .AddMethod(__Method_Sum, serviceImpl.Sum).Build();
     }
 
-    // creates a new client
-    public static MathClient NewClient(Channel channel)
-    {
-      return new MathClient(channel);
-    }
-
   }
 }
 #endregion
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
index e7f7797..967d117 100644
--- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -1,5 +1,35 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
 // source: health.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
 #region Designer generated code
 
 using System;
@@ -22,13 +52,13 @@
         __Marshaller_HealthCheckRequest,
         __Marshaller_HealthCheckResponse);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Health.V1.HealthReflection.Descriptor.Services[0]; }
     }
 
-    // client interface
+    /// <summary>Client for Health</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IHealthClient
     {
@@ -38,14 +68,14 @@
       AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of Health</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IHealth
     {
       Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of Health</summary>
     public abstract class HealthBase
     {
       public virtual Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context)
@@ -55,7 +85,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for Health</summary>
     #pragma warning disable 0618
     public class HealthClient : ClientBase<HealthClient>, IHealthClient
     #pragma warning restore 0618
@@ -97,7 +127,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for Health</summary>
+    public static HealthClient NewClient(Channel channel)
+    {
+      return new HealthClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IHealth serviceImpl)
     #pragma warning restore 0618
@@ -106,7 +142,7 @@
           .AddMethod(__Method_Check, serviceImpl.Check).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(HealthBase serviceImpl)
     #pragma warning restore 0618
@@ -115,12 +151,6 @@
           .AddMethod(__Method_Check, serviceImpl.Check).Build();
     }
 
-    // creates a new client
-    public static HealthClient NewClient(Channel channel)
-    {
-      return new HealthClient(channel);
-    }
-
   }
 }
 #endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
index 11c1572..aa4f1c5 100644
--- a/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/MetricsGrpc.cs
@@ -1,5 +1,41 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
 // source: src/proto/grpc/testing/metrics.proto
+// Original file comments:
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Contains the definitions for a metrics service and the type of metrics
+// exposed by the service.
+//
+// Currently, 'Gauge' (i.e a metric that represents the measured value of
+// something at an instant of time) is the only metric type supported by the
+// service.
 #region Designer generated code
 
 using System;
@@ -30,40 +66,74 @@
         __Marshaller_GaugeRequest,
         __Marshaller_GaugeResponse);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Testing.MetricsReflection.Descriptor.Services[0]; }
     }
 
-    // client interface
+    /// <summary>Client for MetricsService</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IMetricsServiceClient
     {
+      /// <summary>
+      ///  Returns the values of all the gauges that are currently being maintained by
+      ///  the service
+      /// </summary>
       AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Returns the values of all the gauges that are currently being maintained by
+      ///  the service
+      /// </summary>
       AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options);
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options);
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of MetricsService</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IMetricsService
     {
+      /// <summary>
+      ///  Returns the values of all the gauges that are currently being maintained by
+      ///  the service
+      /// </summary>
       Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of MetricsService</summary>
     public abstract class MetricsServiceBase
     {
+      /// <summary>
+      ///  Returns the values of all the gauges that are currently being maintained by
+      ///  the service
+      /// </summary>
       public virtual Task GetAllGauges(global::Grpc.Testing.EmptyMessage request, IServerStreamWriter<global::Grpc.Testing.GaugeResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       public virtual Task<global::Grpc.Testing.GaugeResponse> GetGauge(global::Grpc.Testing.GaugeRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -71,7 +141,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for MetricsService</summary>
     #pragma warning disable 0618
     public class MetricsServiceClient : ClientBase<MetricsServiceClient>, IMetricsServiceClient
     #pragma warning restore 0618
@@ -91,26 +161,46 @@
       {
       }
 
+      /// <summary>
+      ///  Returns the values of all the gauges that are currently being maintained by
+      ///  the service
+      /// </summary>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return GetAllGauges(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Returns the values of all the gauges that are currently being maintained by
+      ///  the service
+      /// </summary>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.GaugeResponse> GetAllGauges(global::Grpc.Testing.EmptyMessage request, CallOptions options)
       {
         return CallInvoker.AsyncServerStreamingCall(__Method_GetAllGauges, null, options, request);
       }
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return GetGauge(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       public virtual global::Grpc.Testing.GaugeResponse GetGauge(global::Grpc.Testing.GaugeRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_GetGauge, null, options, request);
       }
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return GetGaugeAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Returns the value of one gauge
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.GaugeResponse> GetGaugeAsync(global::Grpc.Testing.GaugeRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_GetGauge, null, options, request);
@@ -121,7 +211,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for MetricsService</summary>
+    public static MetricsServiceClient NewClient(Channel channel)
+    {
+      return new MetricsServiceClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IMetricsService serviceImpl)
     #pragma warning restore 0618
@@ -131,7 +227,7 @@
           .AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(MetricsServiceBase serviceImpl)
     #pragma warning restore 0618
@@ -141,12 +237,6 @@
           .AddMethod(__Method_GetGauge, serviceImpl.GetGauge).Build();
     }
 
-    // creates a new client
-    public static MetricsServiceClient NewClient(Channel channel)
-    {
-      return new MetricsServiceClient(channel);
-    }
-
   }
 }
 #endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
index 18cf067..42bf5e0 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServicesGrpc.cs
@@ -1,5 +1,37 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
 // source: src/proto/grpc/testing/services.proto
+// Original file comments:
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
 #region Designer generated code
 
 using System;
@@ -29,40 +61,80 @@
         __Marshaller_SimpleRequest,
         __Marshaller_SimpleResponse);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[0]; }
     }
 
-    // client interface
+    /// <summary>Client for BenchmarkService</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IBenchmarkServiceClient
     {
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of BenchmarkService</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IBenchmarkService
     {
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of BenchmarkService</summary>
     public abstract class BenchmarkServiceBase
     {
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual Task StreamingCall(IAsyncStreamReader<global::Grpc.Testing.SimpleRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.SimpleResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -70,7 +142,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for BenchmarkService</summary>
     #pragma warning disable 0618
     public class BenchmarkServiceClient : ClientBase<BenchmarkServiceClient>, IBenchmarkServiceClient
     #pragma warning restore 0618
@@ -90,26 +162,50 @@
       {
       }
 
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
       }
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
       }
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return StreamingCall(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One request followed by one response.
+      ///  The server returns the client payload as-is.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.SimpleRequest, global::Grpc.Testing.SimpleResponse> StreamingCall(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_StreamingCall, null, options);
@@ -120,7 +216,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for BenchmarkService</summary>
+    public static BenchmarkServiceClient NewClient(Channel channel)
+    {
+      return new BenchmarkServiceClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IBenchmarkService serviceImpl)
     #pragma warning restore 0618
@@ -130,7 +232,7 @@
           .AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(BenchmarkServiceBase serviceImpl)
     #pragma warning restore 0618
@@ -140,12 +242,6 @@
           .AddMethod(__Method_StreamingCall, serviceImpl.StreamingCall).Build();
     }
 
-    // creates a new client
-    public static BenchmarkServiceClient NewClient(Channel channel)
-    {
-      return new BenchmarkServiceClient(channel);
-    }
-
   }
   public static class WorkerService
   {
@@ -187,58 +283,158 @@
         __Marshaller_Void,
         __Marshaller_Void);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Testing.ServicesReflection.Descriptor.Services[1]; }
     }
 
-    // client interface
+    /// <summary>Client for WorkerService</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IWorkerServiceClient
     {
+      /// <summary>
+      ///  Start server with specified workload.
+      ///  First request sent specifies the ServerConfig followed by ServerStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test server
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Start server with specified workload.
+      ///  First request sent specifies the ServerConfig followed by ServerStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test server
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options);
+      /// <summary>
+      ///  Start client with specified workload.
+      ///  First request sent specifies the ClientConfig followed by ClientStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test client
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Start client with specified workload.
+      ///  First request sent specifies the ClientConfig followed by ClientStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test client
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options);
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options);
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options);
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options);
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of WorkerService</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IWorkerService
     {
+      /// <summary>
+      ///  Start server with specified workload.
+      ///  First request sent specifies the ServerConfig followed by ServerStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test server
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  Start client with specified workload.
+      ///  First request sent specifies the ClientConfig followed by ClientStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test client
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context);
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of WorkerService</summary>
     public abstract class WorkerServiceBase
     {
+      /// <summary>
+      ///  Start server with specified workload.
+      ///  First request sent specifies the ServerConfig followed by ServerStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test server
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       public virtual Task RunServer(IAsyncStreamReader<global::Grpc.Testing.ServerArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ServerStatus> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  Start client with specified workload.
+      ///  First request sent specifies the ClientConfig followed by ClientStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test client
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       public virtual Task RunClient(IAsyncStreamReader<global::Grpc.Testing.ClientArgs> requestStream, IServerStreamWriter<global::Grpc.Testing.ClientStatus> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       public virtual Task<global::Grpc.Testing.CoreResponse> CoreCount(global::Grpc.Testing.CoreRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       public virtual Task<global::Grpc.Testing.Void> QuitWorker(global::Grpc.Testing.Void request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -246,7 +442,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for WorkerService</summary>
     #pragma warning disable 0618
     public class WorkerServiceClient : ClientBase<WorkerServiceClient>, IWorkerServiceClient
     #pragma warning restore 0618
@@ -266,50 +462,106 @@
       {
       }
 
+      /// <summary>
+      ///  Start server with specified workload.
+      ///  First request sent specifies the ServerConfig followed by ServerStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test server
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return RunServer(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Start server with specified workload.
+      ///  First request sent specifies the ServerConfig followed by ServerStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test server
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ServerArgs, global::Grpc.Testing.ServerStatus> RunServer(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_RunServer, null, options);
       }
+      /// <summary>
+      ///  Start client with specified workload.
+      ///  First request sent specifies the ClientConfig followed by ClientStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test client
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return RunClient(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Start client with specified workload.
+      ///  First request sent specifies the ClientConfig followed by ClientStatus
+      ///  response. After that, a "Mark" can be sent anytime to request the latest
+      ///  stats. Closing the stream will initiate shutdown of the test client
+      ///  and once the shutdown has finished, the OK status is sent to terminate
+      ///  this RPC.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.ClientArgs, global::Grpc.Testing.ClientStatus> RunClient(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_RunClient, null, options);
       }
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return CoreCount(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       public virtual global::Grpc.Testing.CoreResponse CoreCount(global::Grpc.Testing.CoreRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_CoreCount, null, options, request);
       }
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return CoreCountAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Just return the core count - unary call
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.CoreResponse> CoreCountAsync(global::Grpc.Testing.CoreRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_CoreCount, null, options, request);
       }
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return QuitWorker(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       public virtual global::Grpc.Testing.Void QuitWorker(global::Grpc.Testing.Void request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_QuitWorker, null, options, request);
       }
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return QuitWorkerAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  Quit this worker
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Void> QuitWorkerAsync(global::Grpc.Testing.Void request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_QuitWorker, null, options, request);
@@ -320,7 +572,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for WorkerService</summary>
+    public static WorkerServiceClient NewClient(Channel channel)
+    {
+      return new WorkerServiceClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IWorkerService serviceImpl)
     #pragma warning restore 0618
@@ -332,7 +590,7 @@
           .AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(WorkerServiceBase serviceImpl)
     #pragma warning restore 0618
@@ -344,12 +602,6 @@
           .AddMethod(__Method_QuitWorker, serviceImpl.QuitWorker).Build();
     }
 
-    // creates a new client
-    public static WorkerServiceClient NewClient(Channel channel)
-    {
-      return new WorkerServiceClient(channel);
-    }
-
   }
 }
 #endregion
diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
index 3b915f6..f1878cb 100644
--- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
+++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs
@@ -1,5 +1,38 @@
 // Generated by the protocol buffer compiler.  DO NOT EDIT!
 // source: src/proto/grpc/testing/test.proto
+// Original file comments:
+// Copyright 2015-2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// An integration test service that covers all the method signature permutations
+// of unary/streaming requests/responses.
+//
 #region Designer generated code
 
 using System;
@@ -8,6 +41,10 @@
 using Grpc.Core;
 
 namespace Grpc.Testing {
+  /// <summary>
+  ///  A simple service to test the various types of RPCs and experiment with
+  ///  performance with various types of payload.
+  /// </summary>
   public static class TestService
   {
     static readonly string __ServiceName = "grpc.testing.TestService";
@@ -62,74 +99,186 @@
         __Marshaller_StreamingOutputCallRequest,
         __Marshaller_StreamingOutputCallResponse);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Testing.TestReflection.Descriptor.Services[0]; }
     }
 
-    // client interface
+    /// <summary>Client for TestService</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface ITestServiceClient
     {
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options);
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options);
+      /// <summary>
+      ///  One request followed by a sequence of responses (streamed download).
+      ///  The server returns the payload with client desired type and sizes.
+      /// </summary>
       AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  One request followed by a sequence of responses (streamed download).
+      ///  The server returns the payload with client desired type and sizes.
+      /// </summary>
       AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options);
+      /// <summary>
+      ///  A sequence of requests followed by one response (streamed upload).
+      ///  The server returns the aggregated size of client payload as the result.
+      /// </summary>
       AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  A sequence of requests followed by one response (streamed upload).
+      ///  The server returns the aggregated size of client payload as the result.
+      /// </summary>
       AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options);
+      /// <summary>
+      ///  A sequence of requests with each request served by the server immediately.
+      ///  As one request could lead to multiple responses, this interface
+      ///  demonstrates the idea of full duplexing.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  A sequence of requests with each request served by the server immediately.
+      ///  As one request could lead to multiple responses, this interface
+      ///  demonstrates the idea of full duplexing.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options);
+      /// <summary>
+      ///  A sequence of requests followed by a sequence of responses.
+      ///  The server buffers all the client requests and then serves them in order. A
+      ///  stream of responses are returned to the client when the server starts with
+      ///  first request.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  A sequence of requests followed by a sequence of responses.
+      ///  The server buffers all the client requests and then serves them in order. A
+      ///  stream of responses are returned to the client when the server starts with
+      ///  first request.
+      /// </summary>
       AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of TestService</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface ITestService
     {
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context);
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context);
+      /// <summary>
+      ///  One request followed by a sequence of responses (streamed download).
+      ///  The server returns the payload with client desired type and sizes.
+      /// </summary>
       Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  A sequence of requests followed by one response (streamed upload).
+      ///  The server returns the aggregated size of client payload as the result.
+      /// </summary>
       Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context);
+      /// <summary>
+      ///  A sequence of requests with each request served by the server immediately.
+      ///  As one request could lead to multiple responses, this interface
+      ///  demonstrates the idea of full duplexing.
+      /// </summary>
       Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
+      /// <summary>
+      ///  A sequence of requests followed by a sequence of responses.
+      ///  The server buffers all the client requests and then serves them in order. A
+      ///  stream of responses are returned to the client when the server starts with
+      ///  first request.
+      /// </summary>
       Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of TestService</summary>
     public abstract class TestServiceBase
     {
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       public virtual Task<global::Grpc.Testing.Empty> EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       public virtual Task<global::Grpc.Testing.SimpleResponse> UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  One request followed by a sequence of responses (streamed download).
+      ///  The server returns the payload with client desired type and sizes.
+      /// </summary>
       public virtual Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  A sequence of requests followed by one response (streamed upload).
+      ///  The server returns the aggregated size of client payload as the result.
+      /// </summary>
       public virtual Task<global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<global::Grpc.Testing.StreamingInputCallRequest> requestStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  A sequence of requests with each request served by the server immediately.
+      ///  As one request could lead to multiple responses, this interface
+      ///  demonstrates the idea of full duplexing.
+      /// </summary>
       public virtual Task FullDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
       }
 
+      /// <summary>
+      ///  A sequence of requests followed by a sequence of responses.
+      ///  The server buffers all the client requests and then serves them in order. A
+      ///  stream of responses are returned to the client when the server starts with
+      ///  first request.
+      /// </summary>
       public virtual Task HalfDuplexCall(IAsyncStreamReader<global::Grpc.Testing.StreamingOutputCallRequest> requestStream, IServerStreamWriter<global::Grpc.Testing.StreamingOutputCallResponse> responseStream, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -137,7 +286,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for TestService</summary>
     #pragma warning disable 0618
     public class TestServiceClient : ClientBase<TestServiceClient>, ITestServiceClient
     #pragma warning restore 0618
@@ -157,66 +306,128 @@
       {
       }
 
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return EmptyCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       public virtual global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_EmptyCall, null, options, request);
       }
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return EmptyCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One empty request followed by one empty response.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_EmptyCall, null, options, request);
       }
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       public virtual global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnaryCall, null, options, request);
       }
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnaryCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One request followed by one response.
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.SimpleResponse> UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnaryCall, null, options, request);
       }
+      /// <summary>
+      ///  One request followed by a sequence of responses (streamed download).
+      ///  The server returns the payload with client desired type and sizes.
+      /// </summary>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return StreamingOutputCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  One request followed by a sequence of responses (streamed download).
+      ///  The server returns the payload with client desired type and sizes.
+      /// </summary>
       public virtual AsyncServerStreamingCall<global::Grpc.Testing.StreamingOutputCallResponse> StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options)
       {
         return CallInvoker.AsyncServerStreamingCall(__Method_StreamingOutputCall, null, options, request);
       }
+      /// <summary>
+      ///  A sequence of requests followed by one response (streamed upload).
+      ///  The server returns the aggregated size of client payload as the result.
+      /// </summary>
       public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return StreamingInputCall(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  A sequence of requests followed by one response (streamed upload).
+      ///  The server returns the aggregated size of client payload as the result.
+      /// </summary>
       public virtual AsyncClientStreamingCall<global::Grpc.Testing.StreamingInputCallRequest, global::Grpc.Testing.StreamingInputCallResponse> StreamingInputCall(CallOptions options)
       {
         return CallInvoker.AsyncClientStreamingCall(__Method_StreamingInputCall, null, options);
       }
+      /// <summary>
+      ///  A sequence of requests with each request served by the server immediately.
+      ///  As one request could lead to multiple responses, this interface
+      ///  demonstrates the idea of full duplexing.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return FullDuplexCall(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  A sequence of requests with each request served by the server immediately.
+      ///  As one request could lead to multiple responses, this interface
+      ///  demonstrates the idea of full duplexing.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> FullDuplexCall(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_FullDuplexCall, null, options);
       }
+      /// <summary>
+      ///  A sequence of requests followed by a sequence of responses.
+      ///  The server buffers all the client requests and then serves them in order. A
+      ///  stream of responses are returned to the client when the server starts with
+      ///  first request.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return HalfDuplexCall(new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  A sequence of requests followed by a sequence of responses.
+      ///  The server buffers all the client requests and then serves them in order. A
+      ///  stream of responses are returned to the client when the server starts with
+      ///  first request.
+      /// </summary>
       public virtual AsyncDuplexStreamingCall<global::Grpc.Testing.StreamingOutputCallRequest, global::Grpc.Testing.StreamingOutputCallResponse> HalfDuplexCall(CallOptions options)
       {
         return CallInvoker.AsyncDuplexStreamingCall(__Method_HalfDuplexCall, null, options);
@@ -227,7 +438,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for TestService</summary>
+    public static TestServiceClient NewClient(Channel channel)
+    {
+      return new TestServiceClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(ITestService serviceImpl)
     #pragma warning restore 0618
@@ -241,7 +458,7 @@
           .AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(TestServiceBase serviceImpl)
     #pragma warning restore 0618
@@ -255,13 +472,11 @@
           .AddMethod(__Method_HalfDuplexCall, serviceImpl.HalfDuplexCall).Build();
     }
 
-    // creates a new client
-    public static TestServiceClient NewClient(Channel channel)
-    {
-      return new TestServiceClient(channel);
-    }
-
   }
+  /// <summary>
+  ///  A simple service NOT implemented at servers so clients can test for
+  ///  that case.
+  /// </summary>
   public static class UnimplementedService
   {
     static readonly string __ServiceName = "grpc.testing.UnimplementedService";
@@ -275,32 +490,50 @@
         __Marshaller_Empty,
         __Marshaller_Empty);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Testing.TestReflection.Descriptor.Services[1]; }
     }
 
-    // client interface
+    /// <summary>Client for UnimplementedService</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IUnimplementedServiceClient
     {
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options);
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of UnimplementedService</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IUnimplementedService
     {
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of UnimplementedService</summary>
     public abstract class UnimplementedServiceBase
     {
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       public virtual Task<global::Grpc.Testing.Empty> UnimplementedCall(global::Grpc.Testing.Empty request, ServerCallContext context)
       {
         throw new RpcException(new Status(StatusCode.Unimplemented, ""));
@@ -308,7 +541,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for UnimplementedService</summary>
     #pragma warning disable 0618
     public class UnimplementedServiceClient : ClientBase<UnimplementedServiceClient>, IUnimplementedServiceClient
     #pragma warning restore 0618
@@ -328,18 +561,30 @@
       {
       }
 
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnimplementedCall(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       public virtual global::Grpc.Testing.Empty UnimplementedCall(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.BlockingUnaryCall(__Method_UnimplementedCall, null, options, request);
       }
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
       {
         return UnimplementedCallAsync(request, new CallOptions(headers, deadline, cancellationToken));
       }
+      /// <summary>
+      ///  A call that no server should implement
+      /// </summary>
       public virtual AsyncUnaryCall<global::Grpc.Testing.Empty> UnimplementedCallAsync(global::Grpc.Testing.Empty request, CallOptions options)
       {
         return CallInvoker.AsyncUnaryCall(__Method_UnimplementedCall, null, options, request);
@@ -350,7 +595,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for UnimplementedService</summary>
+    public static UnimplementedServiceClient NewClient(Channel channel)
+    {
+      return new UnimplementedServiceClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IUnimplementedService serviceImpl)
     #pragma warning restore 0618
@@ -359,7 +610,7 @@
           .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(UnimplementedServiceBase serviceImpl)
     #pragma warning restore 0618
@@ -368,13 +619,10 @@
           .AddMethod(__Method_UnimplementedCall, serviceImpl.UnimplementedCall).Build();
     }
 
-    // creates a new client
-    public static UnimplementedServiceClient NewClient(Channel channel)
-    {
-      return new UnimplementedServiceClient(channel);
-    }
-
   }
+  /// <summary>
+  ///  A service used to control reconnect server.
+  /// </summary>
   public static class ReconnectService
   {
     static readonly string __ServiceName = "grpc.testing.ReconnectService";
@@ -397,13 +645,13 @@
         __Marshaller_Empty,
         __Marshaller_ReconnectInfo);
 
-    // service descriptor
+    /// <summary>Service descriptor</summary>
     public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
     {
       get { return global::Grpc.Testing.TestReflection.Descriptor.Services[2]; }
     }
 
-    // client interface
+    /// <summary>Client for ReconnectService</summary>
     [System.Obsolete("Client side interfaced will be removed in the next release. Use client class directly.")]
     public interface IReconnectServiceClient
     {
@@ -417,7 +665,7 @@
       AsyncUnaryCall<global::Grpc.Testing.ReconnectInfo> StopAsync(global::Grpc.Testing.Empty request, CallOptions options);
     }
 
-    // server-side interface
+    /// <summary>Interface of server-side implementations of ReconnectService</summary>
     [System.Obsolete("Service implementations should inherit from the generated abstract base class instead.")]
     public interface IReconnectService
     {
@@ -425,7 +673,7 @@
       Task<global::Grpc.Testing.ReconnectInfo> Stop(global::Grpc.Testing.Empty request, ServerCallContext context);
     }
 
-    // server-side abstract class
+    /// <summary>Base class for server-side implementations of ReconnectService</summary>
     public abstract class ReconnectServiceBase
     {
       public virtual Task<global::Grpc.Testing.Empty> Start(global::Grpc.Testing.ReconnectParams request, ServerCallContext context)
@@ -440,7 +688,7 @@
 
     }
 
-    // client stub
+    /// <summary>Client for ReconnectService</summary>
     #pragma warning disable 0618
     public class ReconnectServiceClient : ClientBase<ReconnectServiceClient>, IReconnectServiceClient
     #pragma warning restore 0618
@@ -498,7 +746,13 @@
       }
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates a new client for ReconnectService</summary>
+    public static ReconnectServiceClient NewClient(Channel channel)
+    {
+      return new ReconnectServiceClient(channel);
+    }
+
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(IReconnectService serviceImpl)
     #pragma warning restore 0618
@@ -508,7 +762,7 @@
           .AddMethod(__Method_Stop, serviceImpl.Stop).Build();
     }
 
-    // creates service definition that can be registered with a server
+    /// <summary>Creates service definition that can be registered with a server</summary>
     #pragma warning disable 0618
     public static ServerServiceDefinition BindService(ReconnectServiceBase serviceImpl)
     #pragma warning restore 0618
@@ -518,12 +772,6 @@
           .AddMethod(__Method_Stop, serviceImpl.Stop).Build();
     }
 
-    // creates a new client
-    public static ReconnectServiceClient NewClient(Channel channel)
-    {
-      return new ReconnectServiceClient(channel);
-    }
-
   }
 }
 #endregion
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index b988f29..6b6e427 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -35,6 +35,8 @@
 #include <nan.h>
 #include <v8.h>
 #include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/alloc.h"
 
 #include "call.h"
 #include "call_credentials.h"
@@ -51,6 +53,8 @@
 using v8::Uint32;
 using v8::String;
 
+static char *pem_root_certs = NULL;
+
 void InitStatusConstants(Local<Object> exports) {
   Nan::HandleScope scope;
   Local<Object> status = Nan::New<Object>();
@@ -268,9 +272,36 @@
       grpc_is_binary_header(key_str, static_cast<size_t>(key->Length()))));
 }
 
+static grpc_ssl_roots_override_result get_ssl_roots_override(
+    char **pem_root_certs_ptr) {
+  *pem_root_certs_ptr = pem_root_certs;
+  if (pem_root_certs == NULL) {
+    return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+  } else {
+    return GRPC_SSL_ROOTS_OVERRIDE_OK;
+  }
+}
+
+/* This should only be called once, and only before creating any
+ *ServerCredentials */
+NAN_METHOD(SetDefaultRootsPem) {
+  if (!info[0]->IsString()) {
+    return Nan::ThrowTypeError(
+        "setDefaultRootsPem's argument must be a string");
+  }
+  Nan::Utf8String utf8_roots(info[0]);
+  size_t length = static_cast<size_t>(utf8_roots.length());
+  if (length > 0) {
+    const char *data = *utf8_roots;
+    pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char));
+    memcpy(pem_root_certs, data, length + 1);
+  }
+}
+
 void init(Local<Object> exports) {
   Nan::HandleScope scope;
   grpc_init();
+  grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
   InitStatusConstants(exports);
   InitCallErrorConstants(exports);
   InitOpTypeConstants(exports);
@@ -298,6 +329,10 @@
            Nan::GetFunction(
                Nan::New<FunctionTemplate>(MetadataKeyIsBinary)
                             ).ToLocalChecked());
+  Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(),
+           Nan::GetFunction(
+               Nan::New<FunctionTemplate>(SetDefaultRootsPem)
+                            ).ToLocalChecked());
 }
 
 NODE_MODULE(grpc_node, init)
diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc
index cff821a..a817ade 100644
--- a/src/node/ext/server_credentials.cc
+++ b/src/node/ext/server_credentials.cc
@@ -146,7 +146,9 @@
         "createSsl's second argument must be a list of objects");
   }
 
-  grpc_ssl_client_certificate_request_type client_certificate_request;
+  // Default to not requesting the client certificate
+  grpc_ssl_client_certificate_request_type client_certificate_request =
+      GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE;
   if (info[2]->IsBoolean()) {
     client_certificate_request =
         Nan::To<bool>(info[2]).FromJust()
diff --git a/src/node/index.js b/src/node/index.js
index d345a51..66664d9 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -34,13 +34,10 @@
 'use strict';
 
 var path = require('path');
+var fs = require('fs');
 
 var SSL_ROOTS_PATH = path.resolve(__dirname, '..', '..', 'etc', 'roots.pem');
 
-if (!process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH) {
-  process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH = SSL_ROOTS_PATH;
-}
-
 var _ = require('lodash');
 
 var ProtoBuf = require('protobufjs');
@@ -53,6 +50,8 @@
 
 var grpc = require('./src/grpc_extension');
 
+grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
+
 /**
  * Load a gRPC object from an existing ProtoBuf.Reflect object.
  * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 2212834..fd5153f 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -684,6 +684,26 @@
   return true;
 };
 
+var unimplementedStatusResponse = {
+  code: grpc.status.UNIMPLEMENTED,
+  details: 'The server does not implement this method'
+};
+
+var defaultHandler = {
+  unary: function(call, callback) {
+    callback(unimplementedStatusResponse);
+  },
+  client_stream: function(call, callback) {
+    callback(unimplementedStatusResponse);
+  },
+  server_stream: function(call) {
+    call.emit('error', unimplementedStatusResponse);
+  },
+  bidi: function(call) {
+    call.emit('error', unimplementedStatusResponse);
+  }
+};
+
 /**
  * Add a service to the server, with a corresponding implementation. If you are
  * generating this from a proto file, you should instead use
@@ -713,16 +733,18 @@
         method_type = 'unary';
       }
     }
+    var impl;
     if (implementation[name] === undefined) {
-      throw new Error('Method handler for ' + attrs.path +
-          ' not provided.');
+      console.warn('Method handler for %s expected but not provided',
+                   attrs.path);
+      impl = defaultHandler[method_type];
+    } else {
+      impl = _.bind(implementation[name], implementation);
     }
     var serialize = attrs.responseSerialize;
     var deserialize = attrs.requestDeserialize;
-    var register_success = self.register(attrs.path,
-                                         _.bind(implementation[name],
-                                                implementation),
-                                         serialize, deserialize, method_type);
+    var register_success = self.register(attrs.path, impl, serialize,
+                                         deserialize, method_type);
     if (!register_success) {
       throw new Error('Method handler for ' + attrs.path +
           ' already provided.');
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index b96e8e4..d8b36dc 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -143,21 +143,59 @@
       server.addProtoService(mathService, dummyImpls);
     });
   });
-  it('Should fail with missing handlers', function() {
-    assert.throws(function() {
-      server.addProtoService(mathService, {
-        'div': function() {},
-        'divMany': function() {},
-        'fib': function() {}
-      });
-    }, /math.Math.Sum/);
-  });
   it('Should fail if the server has been started', function() {
     server.start();
     assert.throws(function() {
       server.addProtoService(mathService, dummyImpls);
     });
   });
+  describe('Default handlers', function() {
+    var client;
+    beforeEach(function() {
+      server.addProtoService(mathService, {});
+      var port = server.bind('localhost:0', server_insecure_creds);
+      var Client = surface_client.makeProtobufClientConstructor(mathService);
+      client = new Client('localhost:' + port,
+                          grpc.credentials.createInsecure());
+      server.start();
+    });
+    it('should respond to a unary call with UNIMPLEMENTED', function(done) {
+      client.div({divisor: 4, dividend: 3}, function(error, response) {
+        assert(error);
+        assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
+        done();
+      });
+    });
+    it('should respond to a client stream with UNIMPLEMENTED', function(done) {
+      var call = client.sum(function(error, respones) {
+        assert(error);
+        assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED);
+        done();
+      });
+      call.end();
+    });
+    it('should respond to a server stream with UNIMPLEMENTED', function(done) {
+      var call = client.fib({limit: 5});
+      call.on('data', function(value) {
+        assert.fail('No messages expected');
+      });
+      call.on('status', function(status) {
+        assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
+        done();
+      });
+    });
+    it('should respond to a bidi call with UNIMPLEMENTED', function(done) {
+      var call = client.divMany();
+      call.on('data', function(value) {
+        assert.fail('No messages expected');
+      });
+      call.on('status', function(status) {
+        assert.strictEqual(status.code, grpc.status.UNIMPLEMENTED);
+        done();
+      });
+      call.end();
+    });
+  });
 });
 describe('Client constructor building', function() {
   var illegal_service_attrs = {
diff --git a/src/node/tools/bin/protoc_plugin.js b/src/node/tools/bin/protoc_plugin.js
new file mode 100755
index 0000000..0e0bb94
--- /dev/null
+++ b/src/node/tools/bin/protoc_plugin.js
@@ -0,0 +1,54 @@
+#!/usr/bin/env node
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * This file is required because package.json cannot reference a file that
+ * is not distributed with the package, and we use node-pre-gyp to distribute
+ * the plugin binary
+ */
+
+'use strict';
+
+var path = require('path');
+var execFile = require('child_process').execFile;
+
+var protoc = path.resolve(__dirname, 'grpc_node_plugin');
+
+execFile(protoc, process.argv.slice(2), function(error, stdout, stderr) {
+  if (error) {
+    throw error;
+  }
+  console.log(stdout);
+  console.log(stderr);
+});
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
index 4b3499f..d98ed0b 100644
--- a/src/node/tools/package.json
+++ b/src/node/tools/package.json
@@ -16,7 +16,8 @@
     }
   ],
   "bin": {
-    "grpc-tools-protoc": "./bin/protoc.js"
+    "grpc-tools-protoc": "./bin/protoc.js",
+    "grpc-tools-plugin": "./bin/protoc_plugin.js"
   },
   "scripts": {
     "install": "./node_modules/.bin/node-pre-gyp install"
@@ -32,6 +33,7 @@
   "files": [
     "index.js",
     "bin/protoc.js",
+    "bin/protoc_plugin.js",
     "LICENSE"
   ],
   "main": "index.js"
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
new file mode 100644
index 0000000..343dd48
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "GRPCCall.h"
+
+/** Helpers for setting TLS Trusted Roots, Client Certificates, and Private Key */
+@interface GRPCCall (ChannelCredentials)
+
+/**
+ * Use the provided @c pemRootCert as the set of trusted root Certificate Authorities for @c host.
+ */
++ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCert
+                   forHost:(nonnull NSString *)host
+                     error:(NSError **)errorPtr;
+/**
+ * Configures @c host with TLS/SSL Client Credentials and optionally trusted root Certificate
+ * Authorities. If @c pemRootCerts is nil, the default CA Certificates bundled with gRPC will be
+ * used.
+ */
++ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
+            withPrivateKey:(nullable NSString *)pemPrivateKey
+             withCertChain:(nullable NSString *)pemCertChain
+                   forHost:(nonnull NSString *)host
+                     error:(NSError **)errorPtr;
+
+@end
diff --git a/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m
new file mode 100644
index 0000000..a8bcd0a
--- /dev/null
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelCredentials.m
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "GRPCCall+ChannelCredentials.h"
+
+#import "private/GRPCHost.h"
+
+@implementation GRPCCall (ChannelCredentials)
+
++ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
+            withPrivateKey:(nullable NSString *)pemPrivateKey
+             withCertChain:(nullable NSString *)pemCertChain
+                   forHost:(nonnull NSString *)host
+                     error:(NSError **)errorPtr {
+  if (!host) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"host must be provided."];
+  }
+  GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
+  return [hostConfig setTLSPEMRootCerts:pemRootCerts
+                 withPrivateKey:pemPrivateKey
+                  withCertChain:pemCertChain
+                          error:errorPtr];
+}
+
++ (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
+                   forHost:(nonnull NSString *)host
+                     error:(NSError **)errorPtr {
+  return [GRPCCall setTLSPEMRootCerts:pemRootCerts
+               withPrivateKey:nil
+                withCertChain:nil
+                      forHost:host
+                      error:errorPtr];
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/GRPCCall+Tests.m b/src/objective-c/GRPCClient/GRPCCall+Tests.m
index c8e8133..b945669 100644
--- a/src/objective-c/GRPCClient/GRPCCall+Tests.m
+++ b/src/objective-c/GRPCClient/GRPCCall+Tests.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,16 @@
   if (!host || !certsPath || !testName) {
     [NSException raise:NSInvalidArgumentException format:@"host, path and name must be provided."];
   }
+  NSError *error = nil;
+  NSString *certs = [NSString stringWithContentsOfFile:certsPath
+                                                      encoding:NSUTF8StringEncoding
+                                                      error:&error];
+  if (error != nil) {
+      [NSException raise:[error localizedDescription] format:@"failed to load certs"];
+  }
+
   GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
-  hostConfig.pathToCertificates = certsPath;
+  [hostConfig setTLSPEMRootCerts:certs withPrivateKey:nil withCertChain:nil error:nil];
   hostConfig.hostNameOverride = testName;
 }
 
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 73bf8d9..70d1a9b 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -56,18 +56,6 @@
 + (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host;
 
 /**
- * Creates a secure channel to the specified @c host using the specified @c pathToCertificates and 
- * @c channelArgs. Only in tests should @c pathToCertificates be nil or
- * @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. Passing nil for @c pathToCertificates
- * results in using the default root certificates distributed with the library. If certificates
- * could not be found in any case, then @c nil is returned.
- */
-+ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
-                             pathToCertificates:(nullable NSString *)pathToCertificates
-                                    channelArgs:(nullable NSDictionary *)channelArgs;
-
-
-/**
  * Creates a secure channel to the specified @c host using the specified @c credentials and
  * @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.
  */
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 926f550..203ef58 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -40,26 +40,6 @@
 
 #import "GRPCCompletionQueue.h"
 
-/**
- * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
- * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
- * details available describing what went wrong.
- */
-static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
-  // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
-  // issuer). Load them as UTF8 and produce an ASCII equivalent.
-  NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
-                                                      encoding:NSUTF8StringEncoding
-                                                         error:errorPtr];
-  NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
-                                       allowLossyConversion:YES];
-  if (!contentInASCII.bytes) {
-    // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
-    return NULL;
-  }
-  return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
-}
-
 void freeChannelArgs(grpc_channel_args *channel_args) {
   for (size_t i = 0; i < channel_args->num_args; ++i) {
     grpc_arg *arg = &channel_args->args[i];
@@ -158,38 +138,6 @@
 }
 
 + (GRPCChannel *)secureChannelWithHost:(NSString *)host
-                    pathToCertificates:(NSString *)path
-                           channelArgs:(NSDictionary *)channelArgs {
-  // Load default SSL certificates once.
-  static grpc_channel_credentials *kDefaultCertificates;
-  static dispatch_once_t loading;
-  dispatch_once(&loading, ^{
-    NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
-    // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
-    NSBundle *bundle = [NSBundle bundleForClass:self.class];
-    NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
-    NSError *error;
-    kDefaultCertificates = CertificatesAtPath(path, &error);
-    NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
-             "certificates, is needed to establish secure (TLS) connections. Because the file is "
-             "distributed with the gRPC library, this error is usually a sign that the library "
-             "wasn't configured correctly for your project. Error: %@",
-             bundle.bundlePath, defaultPath, error);
-  });
-
-  //TODO(jcanizales): Add NSError** parameter to the initializer.
-  grpc_channel_credentials *certificates = path
-      ? CertificatesAtPath(path, NULL)
-      : kDefaultCertificates;
-
-  return [[GRPCChannel alloc] initWithHost:host
-                                    secure:YES
-                               credentials:certificates
-                               channelArgs:channelArgs];
-}
-
-
-+ (GRPCChannel *)secureChannelWithHost:(NSString *)host
                            credentials:(struct grpc_channel_credentials *)credentials
                            channelArgs:(NSDictionary *)channelArgs {
   return [[GRPCChannel alloc] initWithHost:host
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index e58bb7a..9220e2a 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -37,23 +37,28 @@
 
 @class GRPCCompletionQueue;
 struct grpc_call;
+struct grpc_channel_credentials;
 
 @interface GRPCHost : NSObject
 
 @property(nonatomic, readonly) NSString *address;
 @property(nonatomic, copy, nullable) NSString *userAgentPrefix;
+@property(nonatomic, nullable) struct grpc_channel_credentials *channelCreds;
 
 /** The following properties should only be modified for testing: */
 
 @property(nonatomic, getter=isSecure) BOOL secure;
 
-@property(nonatomic, copy, nullable) NSString *pathToCertificates;
 @property(nonatomic, copy, nullable) NSString *hostNameOverride;
 
 - (nullable instancetype)init NS_UNAVAILABLE;
 /** Host objects initialized with the same address are the same. */
 + (nullable instancetype)hostWithAddress:(NSString *)address;
 - (nullable instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
+- (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
+            withPrivateKey:(nullable NSString *)pemPrivateKey
+             withCertChain:(nullable NSString *)pemCertChain
+                     error:(NSError **)errorPtr;
 
 /** Create a grpc_call object to the provided path on this host. */
 - (nullable struct grpc_call *)unmanagedCallWithPath:(NSString *)path
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 739d808..43166cb 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -34,6 +34,7 @@
 #import "GRPCHost.h"
 
 #include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
 #import <GRPCClient/GRPCCall.h>
 #import <GRPCClient/GRPCCall+ChannelArg.h>
 
@@ -56,6 +57,12 @@
   return [[self alloc] initWithAddress:address];
 }
 
+- (void)dealloc {
+  if (_channelCreds != nil) {
+    grpc_channel_credentials_release(_channelCreds);
+  }
+}
+
 // Default initializer.
 - (nullable instancetype)initWithAddress:(NSString *)address {
   if (!address) {
@@ -105,6 +112,75 @@
   return [channel unmanagedCallWithPath:path completionQueue:queue];
 }
 
+- (BOOL)setTLSPEMRootCerts:(nullable NSString *)pemRootCerts
+            withPrivateKey:(nullable NSString *)pemPrivateKey
+             withCertChain:(nullable NSString *)pemCertChain
+                     error:(NSError **)errorPtr {
+  static NSData *kDefaultRootsASCII;
+  static NSError *kDefaultRootsError;
+  static dispatch_once_t loading;
+  dispatch_once(&loading, ^{
+    NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
+    // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
+    NSBundle *bundle = [NSBundle bundleForClass:self.class];
+    NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
+    NSError *error;
+    // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
+    // issuer). Load them as UTF8 and produce an ASCII equivalent.
+    NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
+                                                        encoding:NSUTF8StringEncoding
+                                                           error:&error];
+    if (contentInUTF8 == nil) {
+      kDefaultRootsError = error;
+      return;
+    }
+    kDefaultRootsASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
+                                     allowLossyConversion:YES];
+  });
+
+  NSData *rootsASCII;
+  if (pemRootCerts != nil) {
+    rootsASCII = [pemRootCerts dataUsingEncoding:NSASCIIStringEncoding
+                     allowLossyConversion:YES];
+  } else {
+    if (kDefaultRootsASCII == nil) {
+      if (errorPtr) {
+        *errorPtr = kDefaultRootsError;
+      }
+      NSAssert(kDefaultRootsASCII, @"Could not read gRPCCertificates.bundle/roots.pem. This file, "
+               "with the root certificates, is needed to establish secure (TLS) connections. "
+               "Because the file is distributed with the gRPC library, this error is usually a sign "
+               "that the library wasn't configured correctly for your project. Error: %@",
+                kDefaultRootsError);
+      return NO;
+    }
+    rootsASCII = kDefaultRootsASCII;
+  }
+
+  grpc_channel_credentials *creds;
+  if (pemPrivateKey == nil && pemCertChain == nil) {
+    creds = grpc_ssl_credentials_create(rootsASCII.bytes, NULL, NULL);
+  } else {
+    grpc_ssl_pem_key_cert_pair key_cert_pair;
+    NSData *privateKeyASCII = [pemPrivateKey dataUsingEncoding:NSASCIIStringEncoding
+                                       allowLossyConversion:YES];
+    NSData *certChainASCII = [pemCertChain dataUsingEncoding:NSASCIIStringEncoding
+                                     allowLossyConversion:YES];
+    key_cert_pair.private_key = privateKeyASCII.bytes;
+    key_cert_pair.cert_chain = certChainASCII.bytes;
+    creds = grpc_ssl_credentials_create(rootsASCII.bytes, &key_cert_pair, NULL);
+  }
+
+  @synchronized(self) {
+    if (_channelCreds != nil) {
+      grpc_channel_credentials_release(_channelCreds);
+    }
+    _channelCreds = creds;
+  }
+
+  return YES;
+}
+
 - (NSDictionary *)channelArgs {
   NSMutableDictionary *args = [NSMutableDictionary dictionary];
 
@@ -125,9 +201,16 @@
 - (GRPCChannel *)newChannel {
   NSDictionary *args = [self channelArgs];
   if (_secure) {
-    return [GRPCChannel secureChannelWithHost:_address
-                           pathToCertificates:_pathToCertificates
-                                  channelArgs:args];
+      GRPCChannel *channel;
+      @synchronized(self) {
+        if (_channelCreds == nil) {
+          [self setTLSPEMRootCerts:nil withPrivateKey:nil withCertChain:nil error:nil];
+        }
+        channel = [GRPCChannel secureChannelWithHost:_address
+                                          credentials:_channelCreds
+                                          channelArgs:args];
+      }
+      return channel;
   } else {
     return [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
   }
@@ -145,9 +228,6 @@
   }
 }
 
-// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
-// have been set. Don't let set either of the latter if |secure| has been set to |NO|.
-
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index 33a462b..cb3f6b8 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -23,6 +23,16 @@
 
   $ sudo pip install grpcio
 
+If you're on Windows make sure that you installed the :code:`pip.exe` component
+when you installed Python (if not go back and install it!) then invoke:
+
+::
+
+  $ pip.exe install grpcio
+
+Windows users may need to invoke :code:`pip.exe` from a command line ran as
+administrator.
+
 n.b. On Windows and on Mac OS X one *must* have a recent release of :code:`pip`
 to retrieve the proper wheel from PyPI. Be sure to upgrade to the latest
 version!
@@ -43,6 +53,9 @@
   $ pip install -rrequirements.txt
   $ GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .
 
+You cannot currently install Python from source on Windows. Things might work
+out for you in MSYS2 (follow the Linux instructions), but it isn't officially
+supported at the moment.
 
 Troubleshooting
 ~~~~~~~~~~~~~~~
diff --git a/src/python/grpcio/grpc/_adapter/fore.py b/src/python/grpcio/grpc/_adapter/fore.py
deleted file mode 100644
index acdd69c..0000000
--- a/src/python/grpcio/grpc/_adapter/fore.py
+++ /dev/null
@@ -1,363 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""The RPC-service-side bridge between RPC Framework and GRPC-on-the-wire."""
-
-import enum
-import logging
-import threading
-import time
-
-from grpc._adapter import _common
-from grpc._adapter import _intermediary_low as _low
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.base import null
-from grpc.framework.foundation import activated
-from grpc.framework.foundation import logging_pool
-
-_THREAD_POOL_SIZE = 10
-
-
-@enum.unique
-class _LowWrite(enum.Enum):
-  """The possible categories of low-level write state."""
-
-  OPEN = 'OPEN'
-  ACTIVE = 'ACTIVE'
-  CLOSED = 'CLOSED'
-
-
-def _write(call, rpc_state, payload):
-  serialized_payload = rpc_state.serializer(payload)
-  if rpc_state.write.low is _LowWrite.OPEN:
-    call.write(serialized_payload, call, 0)
-    rpc_state.write.low = _LowWrite.ACTIVE
-  else:
-    rpc_state.write.pending.append(serialized_payload)
-
-
-def _status(call, rpc_state):
-  call.status(_low.Status(_low.Code.OK, ''), call)
-  rpc_state.write.low = _LowWrite.CLOSED
-
-
-class ForeLink(base_interfaces.ForeLink, activated.Activated):
-  """A service-side bridge between RPC Framework and the C-ish _low code."""
-
-  def __init__(
-      self, pool, request_deserializers, response_serializers,
-      root_certificates, key_chain_pairs, port=None):
-    """Constructor.
-
-    Args:
-      pool: A thread pool.
-      request_deserializers: A dict from RPC method names to request object
-        deserializer behaviors.
-      response_serializers: A dict from RPC method names to response object
-        serializer behaviors.
-      root_certificates: The PEM-encoded client root certificates as a
-        bytestring or None.
-      key_chain_pairs: A sequence of PEM-encoded private key-certificate chain
-        pairs.
-      port: The port on which to serve, or None to have a port selected
-        automatically.
-    """
-    self._condition = threading.Condition()
-    self._pool = pool
-    self._request_deserializers = request_deserializers
-    self._response_serializers = response_serializers
-    self._root_certificates = root_certificates
-    self._key_chain_pairs = key_chain_pairs
-    self._requested_port = port
-
-    self._rear_link = null.NULL_REAR_LINK
-    self._completion_queue = None
-    self._server = None
-    self._rpc_states = {}
-    self._spinning = False
-    self._port = None
-
-  def _on_stop_event(self):
-    self._spinning = False
-    self._condition.notify_all()
-
-  def _on_service_acceptance_event(self, event, server):
-    """Handle a service invocation event."""
-    service_acceptance = event.service_acceptance
-    if service_acceptance is None:
-      return
-
-    call = service_acceptance.call
-    call.accept(self._completion_queue, call)
-    # TODO(nathaniel): Metadata support.
-    call.premetadata()
-    call.read(call)
-    method = service_acceptance.method
-
-    self._rpc_states[call] = _common.CommonRPCState(
-        _common.WriteState(_LowWrite.OPEN, _common.HighWrite.OPEN, []), 1,
-        self._request_deserializers[method],
-        self._response_serializers[method])
-
-    ticket = base_interfaces.FrontToBackTicket(
-        call, 0, base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT, method,
-        base_interfaces.ServicedSubscription.Kind.FULL, None, None,
-        service_acceptance.deadline - time.time())
-    self._rear_link.accept_front_to_back_ticket(ticket)
-
-    server.service(None)
-
-  def _on_read_event(self, event):
-    """Handle data arriving during an RPC."""
-    call = event.tag
-    rpc_state = self._rpc_states.get(call, None)
-    if rpc_state is None:
-      return
-
-    sequence_number = rpc_state.sequence_number
-    rpc_state.sequence_number += 1
-    if event.bytes is None:
-      ticket = base_interfaces.FrontToBackTicket(
-          call, sequence_number,
-          base_interfaces.FrontToBackTicket.Kind.COMPLETION, None, None, None,
-          None, None)
-    else:
-      call.read(call)
-      ticket = base_interfaces.FrontToBackTicket(
-          call, sequence_number,
-          base_interfaces.FrontToBackTicket.Kind.CONTINUATION, None, None,
-          None, rpc_state.deserializer(event.bytes), None)
-
-    self._rear_link.accept_front_to_back_ticket(ticket)
-
-  def _on_write_event(self, event):
-    call = event.tag
-    rpc_state = self._rpc_states.get(call, None)
-    if rpc_state is None:
-      return
-
-    if rpc_state.write.pending:
-      serialized_payload = rpc_state.write.pending.pop(0)
-      call.write(serialized_payload, call, 0)
-    elif rpc_state.write.high is _common.HighWrite.CLOSED:
-      _status(call, rpc_state)
-    else:
-      rpc_state.write.low = _LowWrite.OPEN
-
-  def _on_complete_event(self, event):
-    if not event.complete_accepted:
-      logging.error('Complete not accepted! %s', (event,))
-      call = event.tag
-      rpc_state = self._rpc_states.pop(call, None)
-      if rpc_state is None:
-        return
-
-      sequence_number = rpc_state.sequence_number
-      rpc_state.sequence_number += 1
-      ticket = base_interfaces.FrontToBackTicket(
-          call, sequence_number,
-          base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None,
-          None, None, None, None)
-      self._rear_link.accept_front_to_back_ticket(ticket)
-
-  def _on_finish_event(self, event):
-    """Handle termination of an RPC."""
-    call = event.tag
-    rpc_state = self._rpc_states.pop(call, None)
-    if rpc_state is None:
-      return
-
-    code = event.status.code
-    if code is _low.Code.OK:
-      return
-
-    sequence_number = rpc_state.sequence_number
-    rpc_state.sequence_number += 1
-    if code is _low.Code.CANCELLED:
-      ticket = base_interfaces.FrontToBackTicket(
-          call, sequence_number,
-          base_interfaces.FrontToBackTicket.Kind.CANCELLATION, None, None,
-          None, None, None)
-    elif code is _low.Code.DEADLINE_EXCEEDED:
-      ticket = base_interfaces.FrontToBackTicket(
-          call, sequence_number,
-          base_interfaces.FrontToBackTicket.Kind.EXPIRATION, None, None, None,
-          None, None)
-    else:
-      # TODO(nathaniel): Better mapping of codes to ticket-categories
-      ticket = base_interfaces.FrontToBackTicket(
-          call, sequence_number,
-          base_interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE, None,
-          None, None, None, None)
-    self._rear_link.accept_front_to_back_ticket(ticket)
-
-  def _spin(self, completion_queue, server):
-    while True:
-      event = completion_queue.get(None)
-
-      with self._condition:
-        if event.kind is _low.Event.Kind.STOP:
-          self._on_stop_event()
-          return
-        elif self._server is None:
-          continue
-        elif event.kind is _low.Event.Kind.SERVICE_ACCEPTED:
-          self._on_service_acceptance_event(event, server)
-        elif event.kind is _low.Event.Kind.READ_ACCEPTED:
-          self._on_read_event(event)
-        elif event.kind is _low.Event.Kind.WRITE_ACCEPTED:
-          self._on_write_event(event)
-        elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED:
-          self._on_complete_event(event)
-        elif event.kind is _low.Event.Kind.FINISH:
-          self._on_finish_event(event)
-        else:
-          logging.error('Illegal event! %s', (event,))
-
-  def _continue(self, call, payload):
-    rpc_state = self._rpc_states.get(call, None)
-    if rpc_state is None:
-      return
-
-    _write(call, rpc_state, payload)
-
-  def _complete(self, call, payload):
-    """Handle completion of the writes of an RPC."""
-    rpc_state = self._rpc_states.get(call, None)
-    if rpc_state is None:
-      return
-
-    if rpc_state.write.low is _LowWrite.OPEN:
-      if payload is None:
-        _status(call, rpc_state)
-      else:
-        _write(call, rpc_state, payload)
-    elif rpc_state.write.low is _LowWrite.ACTIVE:
-      if payload is not None:
-        rpc_state.write.pending.append(rpc_state.serializer(payload))
-    else:
-      raise ValueError('Called to complete after having already completed!')
-    rpc_state.write.high = _common.HighWrite.CLOSED
-
-  def _cancel(self, call):
-    call.cancel()
-    self._rpc_states.pop(call, None)
-
-  def join_rear_link(self, rear_link):
-    """See base_interfaces.ForeLink.join_rear_link for specification."""
-    self._rear_link = null.NULL_REAR_LINK if rear_link is None else rear_link
-
-  def _start(self):
-    """Starts this ForeLink.
-
-    This method must be called before attempting to exchange tickets with this
-    object.
-    """
-    with self._condition:
-      address = '[::]:%d' % (
-          0 if self._requested_port is None else self._requested_port)
-      self._completion_queue = _low.CompletionQueue()
-      if self._root_certificates is None and not self._key_chain_pairs:
-        self._server = _low.Server(self._completion_queue)
-        self._port = self._server.add_http2_addr(address)
-      else:
-        server_credentials = _low.ServerCredentials(
-          self._root_certificates, self._key_chain_pairs, False)
-        self._server = _low.Server(self._completion_queue)
-        self._port = self._server.add_secure_http2_addr(
-            address, server_credentials)
-      self._server.start()
-
-      self._server.service(None)
-
-      self._pool.submit(self._spin, self._completion_queue, self._server)
-      self._spinning = True
-
-      return self
-
-  # TODO(nathaniel): Expose graceful-shutdown semantics in which this object
-  # enters a state in which it finishes ongoing RPCs but refuses new ones.
-  def _stop(self):
-    """Stops this ForeLink.
-
-    This method must be called for proper termination of this object, and no
-    attempts to exchange tickets with this object may be made after this method
-    has been called.
-    """
-    with self._condition:
-      self._server.stop()
-      # TODO(nathaniel): Yep, this is weird. Deleting a server shouldn't have a
-      # behaviorally significant side-effect.
-      self._server = None
-      self._completion_queue.stop()
-
-      while self._spinning:
-        self._condition.wait()
-
-      self._port = None
-
-  def __enter__(self):
-    """See activated.Activated.__enter__ for specification."""
-    return self._start()
-
-  def __exit__(self, exc_type, exc_val, exc_tb):
-    """See activated.Activated.__exit__ for specification."""
-    self._stop()
-    return False
-
-  def start(self):
-    """See activated.Activated.start for specification."""
-    return self._start()
-
-  def stop(self):
-    """See activated.Activated.stop for specification."""
-    self._stop()
-
-  def port(self):
-    """Identifies the port on which this ForeLink is servicing RPCs.
-
-    Returns:
-      The number of the port on which this ForeLink is servicing RPCs, or None
-        if this ForeLink is not currently activated and servicing RPCs.
-    """
-    with self._condition:
-      return self._port
-
-  def accept_back_to_front_ticket(self, ticket):
-    """See base_interfaces.ForeLink.accept_back_to_front_ticket for spec."""
-    with self._condition:
-      if self._server is None:
-        return
-
-      if ticket.kind is base_interfaces.BackToFrontTicket.Kind.CONTINUATION:
-        self._continue(ticket.operation_id, ticket.payload)
-      elif ticket.kind is base_interfaces.BackToFrontTicket.Kind.COMPLETION:
-        self._complete(ticket.operation_id, ticket.payload)
-      else:
-        self._cancel(ticket.operation_id)
diff --git a/src/python/grpcio/grpc/_adapter/rear.py b/src/python/grpcio/grpc/_adapter/rear.py
deleted file mode 100644
index 17fa47f..0000000
--- a/src/python/grpcio/grpc/_adapter/rear.py
+++ /dev/null
@@ -1,395 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""The RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire."""
-
-import enum
-import logging
-import threading
-import time
-
-from grpc._adapter import _common
-from grpc._adapter import _intermediary_low as _low
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.base import null
-from grpc.framework.foundation import activated
-from grpc.framework.foundation import logging_pool
-
-_THREAD_POOL_SIZE = 10
-
-_INVOCATION_EVENT_KINDS = (
-    _low.Event.Kind.METADATA_ACCEPTED,
-    _low.Event.Kind.FINISH
-)
-
-
-@enum.unique
-class _LowWrite(enum.Enum):
-  """The possible categories of low-level write state."""
-
-  OPEN = 'OPEN'
-  ACTIVE = 'ACTIVE'
-  CLOSED = 'CLOSED'
-
-
-class _RPCState(object):
-  """The full state of any tracked RPC.
-
-  Attributes:
-    call: The _low.Call object for the RPC.
-    outstanding: The set of Event.Kind values describing expected future events
-      for the RPC.
-    active: A boolean indicating whether or not the RPC is active.
-    common: An _common.RPCState describing additional state for the RPC.
-  """
-
-  def __init__(self, call, outstanding, active, common):
-    self.call = call
-    self.outstanding = outstanding
-    self.active = active
-    self.common = common
-
-
-def _write(operation_id, call, outstanding, write_state, serialized_payload):
-  if write_state.low is _LowWrite.OPEN:
-    call.write(serialized_payload, operation_id, 0)
-    outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
-    write_state.low = _LowWrite.ACTIVE
-  elif write_state.low is _LowWrite.ACTIVE:
-    write_state.pending.append(serialized_payload)
-  else:
-    raise ValueError('Write attempted after writes completed!')
-
-
-class RearLink(base_interfaces.RearLink, activated.Activated):
-  """An invocation-side bridge between RPC Framework and the C-ish _low code."""
-
-  def __init__(
-      self, host, port, pool, request_serializers, response_deserializers,
-      secure, root_certificates, private_key, certificate_chain,
-      metadata_transformer=None, server_host_override=None):
-    """Constructor.
-
-    Args:
-      host: The host to which to connect for RPC service.
-      port: The port to which to connect for RPC service.
-      pool: A thread pool.
-      request_serializers: A dict from RPC method names to request object
-        serializer behaviors.
-      response_deserializers: A dict from RPC method names to response object
-        deserializer behaviors.
-      secure: A boolean indicating whether or not to use a secure connection.
-      root_certificates: The PEM-encoded root certificates or None to ask for
-        them to be retrieved from a default location.
-      private_key: The PEM-encoded private key to use or None if no private
-        key should be used.
-      certificate_chain: The PEM-encoded certificate chain to use or None if
-        no certificate chain should be used.
-      metadata_transformer: A function that given a metadata object produces
-        another metadata to be used in the underlying communication on the
-        wire.
-      server_host_override: (For testing only) the target name used for SSL
-        host name checking.
-    """
-    self._condition = threading.Condition()
-    self._host = host
-    self._port = port
-    self._pool = pool
-    self._request_serializers = request_serializers
-    self._response_deserializers = response_deserializers
-
-    self._fore_link = null.NULL_FORE_LINK
-    self._completion_queue = None
-    self._channel = None
-    self._rpc_states = {}
-    self._spinning = False
-    if secure:
-      self._client_credentials = _low.ClientCredentials(
-          root_certificates, private_key, certificate_chain)
-    else:
-      self._client_credentials = None
-    self._root_certificates = root_certificates
-    self._private_key = private_key
-    self._certificate_chain = certificate_chain
-    self._metadata_transformer = metadata_transformer
-    self._server_host_override = server_host_override
-
-  def _on_write_event(self, operation_id, event, rpc_state):
-    if event.write_accepted:
-      if rpc_state.common.write.pending:
-        rpc_state.call.write(
-            rpc_state.common.write.pending.pop(0), operation_id, 0)
-        rpc_state.outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
-      elif rpc_state.common.write.high is _common.HighWrite.CLOSED:
-        rpc_state.call.complete(operation_id)
-        rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED)
-        rpc_state.common.write.low = _LowWrite.CLOSED
-      else:
-        rpc_state.common.write.low = _LowWrite.OPEN
-    else:
-      logging.error('RPC write not accepted! Event: %s', (event,))
-      rpc_state.active = False
-      ticket = base_interfaces.BackToFrontTicket(
-          operation_id, rpc_state.common.sequence_number,
-          base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None)
-      rpc_state.common.sequence_number += 1
-      self._fore_link.accept_back_to_front_ticket(ticket)
-
-  def _on_read_event(self, operation_id, event, rpc_state):
-    if event.bytes is not None:
-      rpc_state.call.read(operation_id)
-      rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED)
-
-      ticket = base_interfaces.BackToFrontTicket(
-          operation_id, rpc_state.common.sequence_number,
-          base_interfaces.BackToFrontTicket.Kind.CONTINUATION,
-          rpc_state.common.deserializer(event.bytes))
-      rpc_state.common.sequence_number += 1
-      self._fore_link.accept_back_to_front_ticket(ticket)
-
-  def _on_complete_event(self, operation_id, event, rpc_state):
-    if not event.complete_accepted:
-      logging.error('RPC complete not accepted! Event: %s', (event,))
-      rpc_state.active = False
-      ticket = base_interfaces.BackToFrontTicket(
-          operation_id, rpc_state.common.sequence_number,
-          base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE, None)
-      rpc_state.common.sequence_number += 1
-      self._fore_link.accept_back_to_front_ticket(ticket)
-
-  # TODO(nathaniel): Metadata support.
-  def _on_metadata_event(self, operation_id, event, rpc_state):  # pylint: disable=unused-argument
-    rpc_state.call.read(operation_id)
-    rpc_state.outstanding.add(_low.Event.Kind.READ_ACCEPTED)
-
-  def _on_finish_event(self, operation_id, event, rpc_state):
-    """Handle termination of an RPC."""
-    # TODO(nathaniel): Cover all statuses.
-    if event.status.code is _low.Code.OK:
-      kind = base_interfaces.BackToFrontTicket.Kind.COMPLETION
-    elif event.status.code is _low.Code.CANCELLED:
-      kind = base_interfaces.BackToFrontTicket.Kind.CANCELLATION
-    elif event.status.code is _low.Code.DEADLINE_EXCEEDED:
-      kind = base_interfaces.BackToFrontTicket.Kind.EXPIRATION
-    else:
-      kind = base_interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE
-    ticket = base_interfaces.BackToFrontTicket(
-        operation_id, rpc_state.common.sequence_number, kind, None)
-    rpc_state.common.sequence_number += 1
-    self._fore_link.accept_back_to_front_ticket(ticket)
-
-  def _spin(self, completion_queue):
-    while True:
-      event = completion_queue.get(None)
-      operation_id = event.tag
-
-      with self._condition:
-        rpc_state = self._rpc_states[operation_id]
-        rpc_state.outstanding.remove(event.kind)
-        if rpc_state.active and self._completion_queue is not None:
-          if event.kind is _low.Event.Kind.WRITE_ACCEPTED:
-            self._on_write_event(operation_id, event, rpc_state)
-          elif event.kind is _low.Event.Kind.METADATA_ACCEPTED:
-            self._on_metadata_event(operation_id, event, rpc_state)
-          elif event.kind is _low.Event.Kind.READ_ACCEPTED:
-            self._on_read_event(operation_id, event, rpc_state)
-          elif event.kind is _low.Event.Kind.COMPLETE_ACCEPTED:
-            self._on_complete_event(operation_id, event, rpc_state)
-          elif event.kind is _low.Event.Kind.FINISH:
-            self._on_finish_event(operation_id, event, rpc_state)
-          else:
-            logging.error('Illegal RPC event! %s', (event,))
-
-        if not rpc_state.outstanding:
-          self._rpc_states.pop(operation_id)
-        if not self._rpc_states:
-          self._spinning = False
-          self._condition.notify_all()
-          return
-
-  def _invoke(self, operation_id, name, high_state, payload, timeout):
-    """Invoke an RPC.
-
-    Args:
-      operation_id: Any object to be used as an operation ID for the RPC.
-      name: The RPC method name.
-      high_state: A _common.HighWrite value representing the "high write state"
-        of the RPC.
-      payload: A payload object for the RPC or None if no payload was given at
-        invocation-time.
-      timeout: A duration of time in seconds to allow for the RPC.
-    """
-    request_serializer = self._request_serializers[name]
-    call = _low.Call(self._channel, self._completion_queue, name, self._host, time.time() + timeout)
-    if self._metadata_transformer is not None:
-      metadata = self._metadata_transformer([])
-      for metadata_key, metadata_value in metadata:
-        call.add_metadata(metadata_key, metadata_value)
-    call.invoke(self._completion_queue, operation_id, operation_id)
-    outstanding = set(_INVOCATION_EVENT_KINDS)
-
-    if payload is None:
-      if high_state is _common.HighWrite.CLOSED:
-        call.complete(operation_id)
-        low_state = _LowWrite.CLOSED
-        outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED)
-      else:
-        low_state = _LowWrite.OPEN
-    else:
-      serialized_payload = request_serializer(payload)
-      call.write(serialized_payload, operation_id, 0)
-      outstanding.add(_low.Event.Kind.WRITE_ACCEPTED)
-      low_state = _LowWrite.ACTIVE
-
-    write_state = _common.WriteState(low_state, high_state, [])
-    common_state = _common.CommonRPCState(
-        write_state, 0, self._response_deserializers[name], request_serializer)
-    self._rpc_states[operation_id] = _RPCState(
-        call, outstanding, True, common_state)
-
-    if not self._spinning:
-      self._pool.submit(self._spin, self._completion_queue)
-      self._spinning = True
-
-  def _commence(self, operation_id, name, payload, timeout):
-    self._invoke(operation_id, name, _common.HighWrite.OPEN, payload, timeout)
-
-  def _continue(self, operation_id, payload):
-    rpc_state = self._rpc_states.get(operation_id, None)
-    if rpc_state is None or not rpc_state.active:
-      return
-
-    _write(
-        operation_id, rpc_state.call, rpc_state.outstanding,
-        rpc_state.common.write, rpc_state.common.serializer(payload))
-
-  def _complete(self, operation_id, payload):
-    """Close writes associated with an ongoing RPC.
-
-    Args:
-      operation_id: Any object being use as an operation ID for the RPC.
-      payload: A payload object for the RPC (and thus the last payload object
-        for the RPC) or None if no payload was given along with the instruction
-        to indicate the end of writes for the RPC.
-    """
-    rpc_state = self._rpc_states.get(operation_id, None)
-    if rpc_state is None or not rpc_state.active:
-      return
-
-    write_state = rpc_state.common.write
-    if payload is None:
-      if write_state.low is _LowWrite.OPEN:
-        rpc_state.call.complete(operation_id)
-        rpc_state.outstanding.add(_low.Event.Kind.COMPLETE_ACCEPTED)
-        write_state.low = _LowWrite.CLOSED
-    else:
-      _write(
-          operation_id, rpc_state.call, rpc_state.outstanding, write_state,
-          rpc_state.common.serializer(payload))
-    write_state.high = _common.HighWrite.CLOSED
-
-  def _entire(self, operation_id, name, payload, timeout):
-    self._invoke(operation_id, name, _common.HighWrite.CLOSED, payload, timeout)
-
-  def _cancel(self, operation_id):
-    rpc_state = self._rpc_states.get(operation_id, None)
-    if rpc_state is not None and rpc_state.active:
-      rpc_state.call.cancel()
-      rpc_state.active = False
-
-  def join_fore_link(self, fore_link):
-    """See base_interfaces.RearLink.join_fore_link for specification."""
-    with self._condition:
-      self._fore_link = null.NULL_FORE_LINK if fore_link is None else fore_link
-
-  def _start(self):
-    """Starts this RearLink.
-
-    This method must be called before attempting to exchange tickets with this
-    object.
-    """
-    with self._condition:
-      self._completion_queue = _low.CompletionQueue()
-      self._channel = _low.Channel(
-          '%s:%d' % (self._host, self._port), self._client_credentials,
-          server_host_override=self._server_host_override)
-    return self
-
-  def _stop(self):
-    """Stops this RearLink.
-
-    This method must be called for proper termination of this object, and no
-    attempts to exchange tickets with this object may be made after this method
-    has been called.
-    """
-    with self._condition:
-      self._completion_queue.stop()
-      self._completion_queue = None
-
-      while self._spinning:
-        self._condition.wait()
-
-  def __enter__(self):
-    """See activated.Activated.__enter__ for specification."""
-    return self._start()
-
-  def __exit__(self, exc_type, exc_val, exc_tb):
-    """See activated.Activated.__exit__ for specification."""
-    self._stop()
-    return False
-
-  def start(self):
-    """See activated.Activated.start for specification."""
-    return self._start()
-
-  def stop(self):
-    """See activated.Activated.stop for specification."""
-    self._stop()
-
-  def accept_front_to_back_ticket(self, ticket):
-    """See base_interfaces.RearLink.accept_front_to_back_ticket for spec."""
-    with self._condition:
-      if self._completion_queue is None:
-        return
-
-      if ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMMENCEMENT:
-        self._commence(
-            ticket.operation_id, ticket.name, ticket.payload, ticket.timeout)
-      elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CONTINUATION:
-        self._continue(ticket.operation_id, ticket.payload)
-      elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.COMPLETION:
-        self._complete(ticket.operation_id, ticket.payload)
-      elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.ENTIRE:
-        self._entire(
-            ticket.operation_id, ticket.name, ticket.payload, ticket.timeout)
-      elif ticket.kind is base_interfaces.FrontToBackTicket.Kind.CANCELLATION:
-        self._cancel(ticket.operation_id)
-      else:
-        # NOTE(nathaniel): All other categories are treated as cancellation.
-        self._cancel(ticket.operation_id)
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c
index 563e605..17a9004 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.c
+++ b/src/python/grpcio/grpc/_cython/imports.generated.c
@@ -125,6 +125,7 @@
 grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
 grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
 grpc_is_binary_header_type grpc_is_binary_header_import;
+grpc_call_error_to_string_type grpc_call_error_to_string_import;
 grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
 grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
 grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -395,6 +396,7 @@
   grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
   grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
   grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
+  grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
   grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
   grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
   grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index 177a0b2..53ebe49 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -325,6 +325,9 @@
 typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
 extern grpc_is_binary_header_type grpc_is_binary_header_import;
 #define grpc_is_binary_header grpc_is_binary_header_import
+typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
+extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
+#define grpc_call_error_to_string grpc_call_error_to_string_import
 typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
 extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
 #define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
diff --git a/src/python/grpcio/grpc/early_adopter/__init__.py b/src/python/grpcio/grpc/early_adopter/__init__.py
deleted file mode 100644
index bff74be..0000000
--- a/src/python/grpcio/grpc/early_adopter/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import warnings
-
-warnings.simplefilter('always', DeprecationWarning)
-warnings.warn('the alpha API (includes this package) is deprecated, '
-              'unmaintained, and no longer tested. Please migrate to the beta '
-              'API.', DeprecationWarning, stacklevel=2)
diff --git a/src/python/grpcio/grpc/early_adopter/implementations.py b/src/python/grpcio/grpc/early_adopter/implementations.py
deleted file mode 100644
index 9c396aa..0000000
--- a/src/python/grpcio/grpc/early_adopter/implementations.py
+++ /dev/null
@@ -1,262 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Entry points into GRPC."""
-
-import threading
-
-from grpc._adapter import fore as _fore
-from grpc._adapter import rear as _rear
-from grpc.framework.alpha import _face_utilities
-from grpc.framework.alpha import _reexport
-from grpc.framework.alpha import interfaces
-from grpc.framework.base import implementations as _base_implementations
-from grpc.framework.base import util as _base_utilities
-from grpc.framework.face import implementations as _face_implementations
-from grpc.framework.foundation import logging_pool
-
-_DEFAULT_THREAD_POOL_SIZE = 8
-_ONE_DAY_IN_SECONDS = 24 * 60 * 60
-
-
-class _Server(interfaces.Server):
-
-  def __init__(
-        self, breakdown, port, private_key, certificate_chain,
-        thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
-    self._lock = threading.Lock()
-    self._breakdown = breakdown
-    self._port = port
-    if private_key is None or certificate_chain is None:
-      self._key_chain_pairs = ()
-    else:
-      self._key_chain_pairs = ((private_key, certificate_chain),)
-
-    self._pool_size = thread_pool_size
-    self._pool = None
-    self._back = None
-    self._fore_link = None
-
-  def _start(self):
-    with self._lock:
-      if self._pool is None:
-        self._pool = logging_pool.pool(self._pool_size)
-        servicer = _face_implementations.servicer(
-            self._pool, self._breakdown.implementations, None)
-        self._back = _base_implementations.back_link(
-            servicer, self._pool, self._pool, self._pool, _ONE_DAY_IN_SECONDS,
-            _ONE_DAY_IN_SECONDS)
-        self._fore_link = _fore.ForeLink(
-            self._pool, self._breakdown.request_deserializers,
-            self._breakdown.response_serializers, None, self._key_chain_pairs,
-            port=self._port)
-        self._back.join_fore_link(self._fore_link)
-        self._fore_link.join_rear_link(self._back)
-        self._fore_link.start()
-      else:
-        raise ValueError('Server currently running!')
-
-  def _stop(self):
-    with self._lock:
-      if self._pool is None:
-        raise ValueError('Server not running!')
-      else:
-        self._fore_link.stop()
-        _base_utilities.wait_for_idle(self._back)
-        self._pool.shutdown(wait=True)
-        self._fore_link = None
-        self._back = None
-        self._pool = None
-
-  def __enter__(self):
-    self._start()
-    return self
-
-  def __exit__(self, exc_type, exc_val, exc_tb):
-    self._stop()
-    return False
-
-  def start(self):
-    self._start()
-
-  def stop(self):
-    self._stop()
-
-  def port(self):
-    with self._lock:
-      return self._fore_link.port()
-
-
-class _Stub(interfaces.Stub):
-
-  def __init__(
-      self, breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, metadata_transformer=None, server_host_override=None,
-      thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
-    self._lock = threading.Lock()
-    self._breakdown = breakdown
-    self._host = host
-    self._port = port
-    self._secure = secure
-    self._root_certificates = root_certificates
-    self._private_key = private_key
-    self._certificate_chain = certificate_chain
-    self._metadata_transformer = metadata_transformer
-    self._server_host_override = server_host_override
-
-    self._pool_size = thread_pool_size
-    self._pool = None
-    self._front = None
-    self._rear_link = None
-    self._understub = None
-
-  def __enter__(self):
-    with self._lock:
-      if self._pool is None:
-        self._pool = logging_pool.pool(self._pool_size)
-        self._front = _base_implementations.front_link(
-            self._pool, self._pool, self._pool)
-        self._rear_link = _rear.RearLink(
-            self._host, self._port, self._pool,
-            self._breakdown.request_serializers,
-            self._breakdown.response_deserializers, self._secure,
-            self._root_certificates, self._private_key, self._certificate_chain,
-            metadata_transformer=self._metadata_transformer,
-            server_host_override=self._server_host_override)
-        self._front.join_rear_link(self._rear_link)
-        self._rear_link.join_fore_link(self._front)
-        self._rear_link.start()
-        self._understub = _face_implementations.dynamic_stub(
-            self._breakdown.face_cardinalities, self._front, self._pool, '')
-      else:
-        raise ValueError('Tried to __enter__ already-__enter__ed Stub!')
-    return self
-
-  def __exit__(self, exc_type, exc_val, exc_tb):
-    with self._lock:
-      if self._pool is None:
-        raise ValueError('Tried to __exit__ non-__enter__ed Stub!')
-      else:
-        self._rear_link.stop()
-        _base_utilities.wait_for_idle(self._front)
-        self._pool.shutdown(wait=True)
-        self._rear_link = None
-        self._front = None
-        self._pool = None
-        self._understub = None
-    return False
-
-  def __getattr__(self, attr):
-    with self._lock:
-      if self._pool is None:
-        raise ValueError('Tried to __getattr__ non-__enter__ed Stub!')
-      else:
-        method_cardinality = self._breakdown.cardinalities.get(attr)
-        underlying_attr = getattr(
-            self._understub, self._breakdown.qualified_names.get(attr), None)
-        if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
-          return _reexport.unary_unary_sync_async(underlying_attr)
-        elif method_cardinality is interfaces.Cardinality.UNARY_STREAM:
-          return lambda request, timeout: _reexport.cancellable_iterator(
-              underlying_attr(request, timeout))
-        elif method_cardinality is interfaces.Cardinality.STREAM_UNARY:
-          return _reexport.stream_unary_sync_async(underlying_attr)
-        elif method_cardinality is interfaces.Cardinality.STREAM_STREAM:
-          return lambda request_iterator, timeout: (
-              _reexport.cancellable_iterator(underlying_attr(
-                  request_iterator, timeout)))
-        else:
-          raise AttributeError(attr)
-
-
-def stub(
-    service_name, methods, host, port, metadata_transformer=None, secure=False,
-    root_certificates=None, private_key=None, certificate_chain=None,
-    server_host_override=None, thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
-  """Constructs an interfaces.Stub.
-
-  Args:
-    service_name: The package-qualified full name of the service.
-    methods: A dictionary from RPC method name to
-      interfaces.RpcMethodInvocationDescription describing the RPCs to be
-      supported by the created stub. The RPC method names in the dictionary are
-      not qualified by the service name or decorated in any other way.
-    host: The host to which to connect for RPC service.
-    port: The port to which to connect for RPC service.
-    metadata_transformer: A callable that given a metadata object produces
-      another metadata object to be used in the underlying communication on the
-      wire.
-    secure: Whether or not to construct the stub with a secure connection.
-    root_certificates: The PEM-encoded root certificates or None to ask for
-      them to be retrieved from a default location.
-    private_key: The PEM-encoded private key to use or None if no private key
-      should be used.
-    certificate_chain: The PEM-encoded certificate chain to use or None if no
-      certificate chain should be used.
-    server_host_override: (For testing only) the target name used for SSL
-      host name checking.
-    thread_pool_size: The maximum number of threads to allow in the backing
-      thread pool.
-
-  Returns:
-    An interfaces.Stub affording RPC invocation.
-  """
-  breakdown = _face_utilities.break_down_invocation(service_name, methods)
-  return _Stub(
-      breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, server_host_override=server_host_override,
-      metadata_transformer=metadata_transformer,
-      thread_pool_size=thread_pool_size)
-
-
-def server(
-    service_name, methods, port, private_key=None, certificate_chain=None,
-    thread_pool_size=_DEFAULT_THREAD_POOL_SIZE):
-  """Constructs an interfaces.Server.
-
-  Args:
-    service_name: The package-qualified full name of the service.
-    methods: A dictionary from RPC method name to
-      interfaces.RpcMethodServiceDescription describing the RPCs to
-      be serviced by the created server. The RPC method names in the dictionary
-      are not qualified by the service name or decorated in any other way.
-    port: The port on which to serve or zero to ask for a port to be
-      automatically selected.
-    private_key: A pem-encoded private key, or None for an insecure server.
-    certificate_chain: A pem-encoded certificate chain, or None for an insecure
-      server.
-    thread_pool_size: The maximum number of threads to allow in the backing
-      thread pool.
-
-  Returns:
-    An interfaces.Server that will serve secure traffic.
-  """
-  breakdown = _face_utilities.break_down_service(service_name, methods)
-  return _Server(breakdown, port, private_key, certificate_chain,
-      thread_pool_size=thread_pool_size)
diff --git a/src/python/grpcio/grpc/framework/alpha/__init__.py b/src/python/grpcio/grpc/framework/alpha/__init__.py
deleted file mode 100644
index bff74be..0000000
--- a/src/python/grpcio/grpc/framework/alpha/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import warnings
-
-warnings.simplefilter('always', DeprecationWarning)
-warnings.warn('the alpha API (includes this package) is deprecated, '
-              'unmaintained, and no longer tested. Please migrate to the beta '
-              'API.', DeprecationWarning, stacklevel=2)
diff --git a/src/python/grpcio/grpc/framework/alpha/_face_utilities.py b/src/python/grpcio/grpc/framework/alpha/_face_utilities.py
deleted file mode 100644
index 15c47d5..0000000
--- a/src/python/grpcio/grpc/framework/alpha/_face_utilities.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import abc
-import collections
-
-import six
-
-# face_interfaces is referenced from specification in this module.
-from grpc.framework.common import cardinality
-from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
-from grpc.framework.face import utilities as face_utilities
-from grpc.framework.alpha import _reexport
-from grpc.framework.alpha import interfaces
-
-
-def _qualified_name(service_name, method_name):
-  return '/%s/%s' % (service_name, method_name)
-
-
-# TODO(nathaniel): This structure is getting bloated; it could be shrunk if
-# implementations._Stub used a generic rather than a dynamic underlying
-# face-layer stub.
-class InvocationBreakdown(six.with_metaclass(abc.ABCMeta)):
-  """An intermediate representation of invocation-side views of RPC methods.
-
-  Attributes:
-    cardinalities: A dictionary from RPC method name to interfaces.Cardinality
-      value.
-    qualified_names: A dictionary from unqualified RPC method name to
-      service-qualified RPC method name.
-    face_cardinalities: A dictionary from service-qualified RPC method name to
-      to cardinality.Cardinality value.
-    request_serializers: A dictionary from service-qualified RPC method name to
-      callable behavior to be used serializing request values for the RPC.
-    response_deserializers: A dictionary from service-qualified RPC method name
-      to callable behavior to be used deserializing response values for the
-      RPC.
-  """
-
-
-class _EasyInvocationBreakdown(
-    InvocationBreakdown,
-    collections.namedtuple(
-        '_EasyInvocationBreakdown',
-        ('cardinalities', 'qualified_names', 'face_cardinalities',
-         'request_serializers', 'response_deserializers'))):
-  pass
-
-
-class ServiceBreakdown(six.with_metaclass(abc.ABCMeta)):
-  """An intermediate representation of service-side views of RPC methods.
-
-  Attributes:
-    implementations: A dictionary from service-qualified RPC method name to
-      face_interfaces.MethodImplementation implementing the RPC method.
-    request_deserializers: A dictionary from service-qualified RPC method name
-      to callable behavior to be used deserializing request values for the RPC.
-    response_serializers: A dictionary from service-qualified RPC method name
-      to callable behavior to be used serializing response values for the RPC.
-  """
-
-
-class _EasyServiceBreakdown(
-    ServiceBreakdown,
-    collections.namedtuple(
-        '_EasyServiceBreakdown',
-        ('implementations', 'request_deserializers', 'response_serializers'))):
-  pass
-
-
-def break_down_invocation(service_name, method_descriptions):
-  """Derives an InvocationBreakdown from several RPC method descriptions.
-
-  Args:
-    service_name: The package-qualified full name of the service.
-    method_descriptions: A dictionary from RPC method name to
-      interfaces.RpcMethodInvocationDescription describing the RPCs.
-
-  Returns:
-    An InvocationBreakdown corresponding to the given method descriptions.
-  """
-  cardinalities = {}
-  qualified_names = {}
-  face_cardinalities = {}
-  request_serializers = {}
-  response_deserializers = {}
-  for name, method_description in six.iteritems(method_descriptions):
-    qualified_name = _qualified_name(service_name, name)
-    method_cardinality = method_description.cardinality()
-    cardinalities[name] = method_description.cardinality()
-    qualified_names[name] = qualified_name
-    face_cardinalities[qualified_name] = _reexport.common_cardinality(
-        method_cardinality)
-    request_serializers[qualified_name] = method_description.serialize_request
-    response_deserializers[qualified_name] = (
-        method_description.deserialize_response)
-  return _EasyInvocationBreakdown(
-      cardinalities, qualified_names, face_cardinalities, request_serializers,
-      response_deserializers)
-
-
-def break_down_service(service_name, method_descriptions):
-  """Derives a ServiceBreakdown from several RPC method descriptions.
-
-  Args:
-    method_descriptions: A dictionary from RPC method name to
-      interfaces.RpcMethodServiceDescription describing the RPCs.
-
-  Returns:
-    A ServiceBreakdown corresponding to the given method descriptions.
-  """
-  implementations = {}
-  request_deserializers = {}
-  response_serializers = {}
-  for name, method_description in six.iteritems(method_descriptions):
-    qualified_name = _qualified_name(service_name, name)
-    method_cardinality = method_description.cardinality()
-    if method_cardinality is interfaces.Cardinality.UNARY_UNARY:
-      def service(
-          request, face_rpc_context,
-          service_behavior=method_description.service_unary_unary):
-        return service_behavior(
-            request, _reexport.rpc_context(face_rpc_context))
-      implementations[qualified_name] = face_utilities.unary_unary_inline(
-          service)
-    elif method_cardinality is interfaces.Cardinality.UNARY_STREAM:
-      def service(
-          request, face_rpc_context,
-          service_behavior=method_description.service_unary_stream):
-        return service_behavior(
-            request, _reexport.rpc_context(face_rpc_context))
-      implementations[qualified_name] = face_utilities.unary_stream_inline(
-          service)
-    elif method_cardinality is interfaces.Cardinality.STREAM_UNARY:
-      def service(
-          request_iterator, face_rpc_context,
-          service_behavior=method_description.service_stream_unary):
-        return service_behavior(
-            request_iterator, _reexport.rpc_context(face_rpc_context))
-      implementations[qualified_name] = face_utilities.stream_unary_inline(
-          service)
-    elif method_cardinality is interfaces.Cardinality.STREAM_STREAM:
-      def service(
-          request_iterator, face_rpc_context,
-          service_behavior=method_description.service_stream_stream):
-        return service_behavior(
-            request_iterator, _reexport.rpc_context(face_rpc_context))
-      implementations[qualified_name] = face_utilities.stream_stream_inline(
-          service)
-    request_deserializers[qualified_name] = (
-        method_description.deserialize_request)
-    response_serializers[qualified_name] = (
-        method_description.serialize_response)
-
-  return _EasyServiceBreakdown(
-      implementations, request_deserializers, response_serializers)
diff --git a/src/python/grpcio/grpc/framework/alpha/_reexport.py b/src/python/grpcio/grpc/framework/alpha/_reexport.py
deleted file mode 100644
index e027077..0000000
--- a/src/python/grpcio/grpc/framework/alpha/_reexport.py
+++ /dev/null
@@ -1,205 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import six
-
-from grpc.framework.common import cardinality
-from grpc.framework.face import exceptions as face_exceptions
-from grpc.framework.face import interfaces as face_interfaces
-from grpc.framework.foundation import future
-from grpc.framework.alpha import exceptions
-from grpc.framework.alpha import interfaces
-
-_EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY = {
-    interfaces.Cardinality.UNARY_UNARY: cardinality.Cardinality.UNARY_UNARY,
-    interfaces.Cardinality.UNARY_STREAM: cardinality.Cardinality.UNARY_STREAM,
-    interfaces.Cardinality.STREAM_UNARY: cardinality.Cardinality.STREAM_UNARY,
-    interfaces.Cardinality.STREAM_STREAM: cardinality.Cardinality.STREAM_STREAM,
-}
-
-_ABORTION_REEXPORT = {
-    face_interfaces.Abortion.CANCELLED: interfaces.Abortion.CANCELLED,
-    face_interfaces.Abortion.EXPIRED: interfaces.Abortion.EXPIRED,
-    face_interfaces.Abortion.NETWORK_FAILURE:
-        interfaces.Abortion.NETWORK_FAILURE,
-    face_interfaces.Abortion.SERVICED_FAILURE:
-        interfaces.Abortion.SERVICED_FAILURE,
-    face_interfaces.Abortion.SERVICER_FAILURE:
-        interfaces.Abortion.SERVICER_FAILURE,
-}
-
-
-class _RpcError(exceptions.RpcError):
-  pass
-
-
-def _reexport_error(face_rpc_error):
-  if isinstance(face_rpc_error, face_exceptions.CancellationError):
-    return exceptions.CancellationError()
-  elif isinstance(face_rpc_error, face_exceptions.ExpirationError):
-    return exceptions.ExpirationError()
-  else:
-    return _RpcError()
-
-
-def _as_face_abortion_callback(abortion_callback):
-  def face_abortion_callback(face_abortion):
-    abortion_callback(_ABORTION_REEXPORT[face_abortion])
-  return face_abortion_callback
-
-
-class _ReexportedFuture(future.Future):
-
-  def __init__(self, face_future):
-    self._face_future = face_future
-
-  def cancel(self):
-    return self._face_future.cancel()
-
-  def cancelled(self):
-    return self._face_future.cancelled()
-
-  def running(self):
-    return self._face_future.running()
-
-  def done(self):
-    return self._face_future.done()
-
-  def result(self, timeout=None):
-    try:
-      return self._face_future.result(timeout=timeout)
-    except face_exceptions.RpcError as e:
-      raise _reexport_error(e)
-
-  def exception(self, timeout=None):
-    face_error = self._face_future.exception(timeout=timeout)
-    return None if face_error is None else _reexport_error(face_error)
-
-  def traceback(self, timeout=None):
-    return self._face_future.traceback(timeout=timeout)
-
-  def add_done_callback(self, fn):
-    self._face_future.add_done_callback(lambda unused_face_future: fn(self))
-
-
-def _call_reexporting_errors(behavior, *args, **kwargs):
-  try:
-    return behavior(*args, **kwargs)
-  except face_exceptions.RpcError as e:
-    raise _reexport_error(e)
-
-
-def _reexported_future(face_future):
-  return _ReexportedFuture(face_future)
-
-
-class _CancellableIterator(interfaces.CancellableIterator):
-
-  def __init__(self, face_cancellable_iterator):
-    self._face_cancellable_iterator = face_cancellable_iterator
-
-  def __iter__(self):
-    return self
-
-  def next(self):
-    return _call_reexporting_errors(self._face_cancellable_iterator.next)
-
-  def cancel(self):
-    self._face_cancellable_iterator.cancel()
-
-
-class _RpcContext(interfaces.RpcContext):
-
-  def __init__(self, face_rpc_context):
-    self._face_rpc_context = face_rpc_context
-
-  def is_active(self):
-    return self._face_rpc_context.is_active()
-
-  def time_remaining(self):
-    return self._face_rpc_context.time_remaining()
-
-  def add_abortion_callback(self, abortion_callback):
-    self._face_rpc_context.add_abortion_callback(
-        _as_face_abortion_callback(abortion_callback))
-
-
-class _UnaryUnarySyncAsync(interfaces.UnaryUnarySyncAsync):
-
-  def __init__(self, face_unary_unary_multi_callable):
-    self._underlying = face_unary_unary_multi_callable
-
-  def __call__(self, request, timeout):
-    return _call_reexporting_errors(
-        self._underlying, request, timeout)
-
-  def async(self, request, timeout):
-    return _ReexportedFuture(self._underlying.future(request, timeout))
-
-
-class _StreamUnarySyncAsync(interfaces.StreamUnarySyncAsync):
-
-  def __init__(self, face_stream_unary_multi_callable):
-    self._underlying = face_stream_unary_multi_callable
-
-  def __call__(self, request_iterator, timeout):
-    return _call_reexporting_errors(
-        self._underlying, request_iterator, timeout)
-
-  def async(self, request_iterator, timeout):
-    return _ReexportedFuture(self._underlying.future(request_iterator, timeout))
-
-
-def common_cardinality(early_adopter_cardinality):
-  return _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
-      early_adopter_cardinality]
-
-
-def common_cardinalities(early_adopter_cardinalities):
-  common_cardinalities = {}
-  for name, early_adopter_cardinality in six.iteritems(early_adopter_cardinalities):
-    common_cardinalities[name] = _EARLY_ADOPTER_CARDINALITY_TO_COMMON_CARDINALITY[
-        early_adopter_cardinality]
-  return common_cardinalities
-
-
-def rpc_context(face_rpc_context):
-  return _RpcContext(face_rpc_context)
-
-
-def cancellable_iterator(face_cancellable_iterator):
-  return _CancellableIterator(face_cancellable_iterator)
-
-
-def unary_unary_sync_async(face_unary_unary_multi_callable):
-  return _UnaryUnarySyncAsync(face_unary_unary_multi_callable)
-
-
-def stream_unary_sync_async(face_stream_unary_multi_callable):
-  return _StreamUnarySyncAsync(face_stream_unary_multi_callable)
diff --git a/src/python/grpcio/grpc/framework/alpha/exceptions.py b/src/python/grpcio/grpc/framework/alpha/exceptions.py
deleted file mode 100644
index 09359c5..0000000
--- a/src/python/grpcio/grpc/framework/alpha/exceptions.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Exceptions raised by GRPC.
-
-Only GRPC should instantiate and raise these exceptions.
-"""
-import abc
-
-import six
-
-class RpcError(six.with_metaclass(abc.ABCMeta, Exception)):
-  """Common super type for all exceptions raised by GRPC."""
-
-
-class CancellationError(RpcError):
-  """Indicates that an RPC has been cancelled."""
-
-
-class ExpirationError(RpcError):
-  """Indicates that an RPC has expired ("timed out")."""
diff --git a/src/python/grpcio/grpc/framework/alpha/interfaces.py b/src/python/grpcio/grpc/framework/alpha/interfaces.py
deleted file mode 100644
index 48f144f..0000000
--- a/src/python/grpcio/grpc/framework/alpha/interfaces.py
+++ /dev/null
@@ -1,384 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Interfaces of GRPC."""
-
-import abc
-import enum
-
-import six
-
-# exceptions is referenced from specification in this module.
-from grpc.framework.alpha import exceptions  # pylint: disable=unused-import
-from grpc.framework.foundation import activated
-from grpc.framework.foundation import future
-
-
-@enum.unique
-class Cardinality(enum.Enum):
-  """Constants for the four cardinalities of RPC."""
-
-  UNARY_UNARY = 'request-unary/response-unary'
-  UNARY_STREAM = 'request-unary/response-streaming'
-  STREAM_UNARY = 'request-streaming/response-unary'
-  STREAM_STREAM = 'request-streaming/response-streaming'
-
-
-@enum.unique
-class Abortion(enum.Enum):
-  """Categories of RPC abortion."""
-
-  CANCELLED = 'cancelled'
-  EXPIRED = 'expired'
-  NETWORK_FAILURE = 'network failure'
-  SERVICED_FAILURE = 'serviced failure'
-  SERVICER_FAILURE = 'servicer failure'
-
-
-class CancellableIterator(six.with_metaclass(abc.ABCMeta)):
-  """Implements the Iterator protocol and affords a cancel method."""
-
-  @abc.abstractmethod
-  def __iter__(self):
-    """Returns the self object in accordance with the Iterator protocol."""
-    raise NotImplementedError()
-
-  def __next__(self):
-    return self.next()
-
-  @abc.abstractmethod
-  def next(self):
-    """Returns a value or raises StopIteration per the Iterator protocol."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def cancel(self):
-    """Requests cancellation of whatever computation underlies this iterator."""
-    raise NotImplementedError()
-
-
-class RpcContext(six.with_metaclass(abc.ABCMeta)):
-  """Provides RPC-related information and action."""
-
-  @abc.abstractmethod
-  def is_active(self):
-    """Describes whether the RPC is active or has terminated."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def time_remaining(self):
-    """Describes the length of allowed time remaining for the RPC.
-    Returns:
-      A nonnegative float indicating the length of allowed time in seconds
-      remaining for the RPC to complete before it is considered to have timed
-      out.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def add_abortion_callback(self, abortion_callback):
-    """Registers a callback to be called if the RPC is aborted.
-    Args:
-      abortion_callback: A callable to be called and passed an Abortion value
-        in the event of RPC abortion.
-    """
-    raise NotImplementedError()
-
-
-class UnaryUnarySyncAsync(six.with_metaclass(abc.ABCMeta)):
-  """Affords invoking a unary-unary RPC synchronously or asynchronously.
-  Values implementing this interface are directly callable and present an
-  "async" method. Both calls take a request value and a numeric timeout.
-  Direct invocation of a value of this type invokes its associated RPC and
-  blocks until the RPC's response is available. Calling the "async" method
-  of a value of this type invokes its associated RPC and immediately returns a
-  future.Future bound to the asynchronous execution of the RPC.
-  """
-
-  @abc.abstractmethod
-  def __call__(self, request, timeout):
-    """Synchronously invokes the underlying RPC.
-    Args:
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-    Returns:
-      The response value for the RPC.
-    Raises:
-      exceptions.RpcError: Indicating that the RPC was aborted.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def async(self, request, timeout):
-    """Asynchronously invokes the underlying RPC.
-    Args:
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-    Returns:
-      A future.Future representing the RPC. In the event of RPC completion, the
-        returned Future's result value will be the response value of the RPC.
-        In the event of RPC abortion, the returned Future's exception value
-        will be an exceptions.RpcError.
-    """
-    raise NotImplementedError()
-
-
-class StreamUnarySyncAsync(six.with_metaclass(abc.ABCMeta)):
-  """Affords invoking a stream-unary RPC synchronously or asynchronously.
-  Values implementing this interface are directly callable and present an
-  "async" method. Both calls take an iterator of request values and a numeric
-  timeout. Direct invocation of a value of this type invokes its associated RPC
-  and blocks until the RPC's response is available. Calling the "async" method
-  of a value of this type invokes its associated RPC and immediately returns a
-  future.Future bound to the asynchronous execution of the RPC.
-  """
-
-  @abc.abstractmethod
-  def __call__(self, request_iterator, timeout):
-    """Synchronously invokes the underlying RPC.
-
-    Args:
-      request_iterator: An iterator that yields request values for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      The response value for the RPC.
-
-    Raises:
-      exceptions.RpcError: Indicating that the RPC was aborted.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def async(self, request_iterator, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-    Args:
-      request_iterator: An iterator that yields request values for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A future.Future representing the RPC. In the event of RPC completion, the
-        returned Future's result value will be the response value of the RPC.
-        In the event of RPC abortion, the returned Future's exception value
-        will be an exceptions.RpcError.
-    """
-    raise NotImplementedError()
-
-
-class RpcMethodDescription(six.with_metaclass(abc.ABCMeta)):
-  """A type for the common aspects of RPC method descriptions."""
-
-  @abc.abstractmethod
-  def cardinality(self):
-    """Identifies the cardinality of this RpcMethodDescription.
-
-    Returns:
-      A Cardinality value identifying whether or not this
-        RpcMethodDescription is request-unary or request-streaming and
-        whether or not it is response-unary or response-streaming.
-    """
-    raise NotImplementedError()
-
-
-class RpcMethodInvocationDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)):
-  """Invocation-side description of an RPC method."""
-
-  @abc.abstractmethod
-  def serialize_request(self, request):
-    """Serializes a request value.
-
-    Args:
-      request: A request value appropriate for the RPC method described by this
-        RpcMethodInvocationDescription.
-
-    Returns:
-      The serialization of the given request value as a
-        bytestring.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def deserialize_response(self, serialized_response):
-    """Deserializes a response value.
-
-    Args:
-      serialized_response: A bytestring that is the serialization of a response
-        value appropriate for the RPC method described by this
-        RpcMethodInvocationDescription.
-
-    Returns:
-      A response value corresponding to the given bytestring.
-    """
-    raise NotImplementedError()
-
-
-class RpcMethodServiceDescription(six.with_metaclass(abc.ABCMeta, RpcMethodDescription)):
-  """Service-side description of an RPC method."""
-
-  @abc.abstractmethod
-  def deserialize_request(self, serialized_request):
-    """Deserializes a request value.
-
-    Args:
-      serialized_request: A bytestring that is the serialization of a request
-        value appropriate for the RPC method described by this
-        RpcMethodServiceDescription.
-
-    Returns:
-      A request value corresponding to the given bytestring.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def serialize_response(self, response):
-    """Serializes a response value.
-
-    Args:
-      response: A response value appropriate for the RPC method described by
-        this RpcMethodServiceDescription.
-
-    Returns:
-      The serialization of the given response value as a
-        bytestring.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def service_unary_unary(self, request, context):
-    """Carries out this RPC.
-
-    This method may only be called if the cardinality of this
-    RpcMethodServiceDescription is Cardinality.UNARY_UNARY.
-
-    Args:
-      request: A request value appropriate for the RPC method described by this
-        RpcMethodServiceDescription.
-      context: An RpcContext object for the RPC.
-
-    Returns:
-      A response value appropriate for the RPC method described by this
-        RpcMethodServiceDescription.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def service_unary_stream(self, request, context):
-    """Carries out this RPC.
-
-    This method may only be called if the cardinality of this
-    RpcMethodServiceDescription is Cardinality.UNARY_STREAM.
-
-    Args:
-      request: A request value appropriate for the RPC method described by this
-        RpcMethodServiceDescription.
-      context: An RpcContext object for the RPC.
-
-    Yields:
-      Zero or more response values appropriate for the RPC method described by
-        this RpcMethodServiceDescription.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def service_stream_unary(self, request_iterator, context):
-    """Carries out this RPC.
-
-    This method may only be called if the cardinality of this
-    RpcMethodServiceDescription is Cardinality.STREAM_UNARY.
-
-    Args:
-      request_iterator: An iterator of request values appropriate for the RPC
-        method described by this RpcMethodServiceDescription.
-      context: An RpcContext object for the RPC.
-
-    Returns:
-      A response value appropriate for the RPC method described by this
-        RpcMethodServiceDescription.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def service_stream_stream(self, request_iterator, context):
-    """Carries out this RPC.
-
-    This method may only be called if the cardinality of this
-    RpcMethodServiceDescription is Cardinality.STREAM_STREAM.
-
-    Args:
-      request_iterator: An iterator of request values appropriate for the RPC
-        method described by this RpcMethodServiceDescription.
-      context: An RpcContext object for the RPC.
-
-    Yields:
-      Zero or more response values appropriate for the RPC method described by
-        this RpcMethodServiceDescription.
-    """
-    raise NotImplementedError()
-
-
-class Stub(six.with_metaclass(abc.ABCMeta)):
-  """A stub with callable RPC method names for attributes.
-
-  Instances of this type are context managers and only afford RPC invocation
-  when used in context.
-
-  Instances of this type, when used in context, respond to attribute access
-  as follows: if the requested attribute is the name of a unary-unary RPC
-  method, the value of the attribute will be a UnaryUnarySyncAsync with which
-  to invoke the RPC method. If the requested attribute is the name of a
-  unary-stream RPC method, the value of the attribute will be a callable taking
-  a request object and a timeout parameter and returning a CancellableIterator
-  that yields the response values of the RPC. If the requested attribute is the
-  name of a stream-unary RPC method, the value of the attribute will be a
-  StreamUnarySyncAsync with which to invoke the RPC method. If the requested
-  attribute is the name of a stream-stream RPC method, the value of the
-  attribute will be a callable taking an iterator of request objects and a
-  timeout and returning a CancellableIterator that yields the response values
-  of the RPC.
-
-  In all cases indication of abortion is indicated by raising of
-  exceptions.RpcError, exceptions.CancellationError,
-  and exceptions.ExpirationError.
-  """
-
-
-class Server(six.with_metaclass(abc.ABCMeta, activated.Activated)):
-  """A GRPC Server."""
-
-  @abc.abstractmethod
-  def port(self):
-    """Reports the port on which the server is serving.
-
-    This method may only be called while the server is activated.
-
-    Returns:
-      The port on which the server is serving.
-    """
-    raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/framework/alpha/utilities.py b/src/python/grpcio/grpc/framework/alpha/utilities.py
deleted file mode 100644
index 7d7f78f..0000000
--- a/src/python/grpcio/grpc/framework/alpha/utilities.py
+++ /dev/null
@@ -1,269 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Utilities for use with GRPC."""
-
-from grpc.framework.alpha import interfaces
-
-
-class _RpcMethodDescription(
-    interfaces.RpcMethodInvocationDescription,
-    interfaces.RpcMethodServiceDescription):
-
-  def __init__(
-      self, cardinality, unary_unary, unary_stream, stream_unary,
-      stream_stream, request_serializer, request_deserializer,
-      response_serializer, response_deserializer):
-    self._cardinality = cardinality
-    self._unary_unary = unary_unary
-    self._unary_stream = unary_stream
-    self._stream_unary = stream_unary
-    self._stream_stream = stream_stream
-    self._request_serializer = request_serializer
-    self._request_deserializer = request_deserializer
-    self._response_serializer = response_serializer
-    self._response_deserializer = response_deserializer
-
-  def cardinality(self):
-    """See interfaces.RpcMethodDescription.cardinality for specification."""
-    return self._cardinality
-
-  def serialize_request(self, request):
-    """See interfaces.RpcMethodInvocationDescription.serialize_request."""
-    return self._request_serializer(request)
-
-  def deserialize_request(self, serialized_request):
-    """See interfaces.RpcMethodServiceDescription.deserialize_request."""
-    return self._request_deserializer(serialized_request)
-
-  def serialize_response(self, response):
-    """See interfaces.RpcMethodServiceDescription.serialize_response."""
-    return self._response_serializer(response)
-
-  def deserialize_response(self, serialized_response):
-    """See interfaces.RpcMethodInvocationDescription.deserialize_response."""
-    return self._response_deserializer(serialized_response)
-
-  def service_unary_unary(self, request, context):
-    """See interfaces.RpcMethodServiceDescription.service_unary_unary."""
-    return self._unary_unary(request, context)
-
-  def service_unary_stream(self, request, context):
-    """See interfaces.RpcMethodServiceDescription.service_unary_stream."""
-    return self._unary_stream(request, context)
-
-  def service_stream_unary(self, request_iterator, context):
-    """See interfaces.RpcMethodServiceDescription.service_stream_unary."""
-    return self._stream_unary(request_iterator, context)
-
-  def service_stream_stream(self, request_iterator, context):
-    """See interfaces.RpcMethodServiceDescription.service_stream_stream."""
-    return self._stream_stream(request_iterator, context)
-
-
-def unary_unary_invocation_description(
-    request_serializer, response_deserializer):
-  """Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
-
-  Args:
-    request_serializer: A callable that when called on a request
-      value returns a bytestring corresponding to that value.
-    response_deserializer: A callable that when called on a
-      bytestring returns the response value corresponding to
-      that bytestring.
-
-  Returns:
-    An interfaces.RpcMethodInvocationDescription constructed from the given
-      arguments representing a unary-request/unary-response RPC method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.UNARY_UNARY, None, None, None, None,
-      request_serializer, None, None, response_deserializer)
-
-
-def unary_stream_invocation_description(
-    request_serializer, response_deserializer):
-  """Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
-
-  Args:
-    request_serializer: A callable that when called on a request
-      value returns a bytestring corresponding to that value.
-    response_deserializer: A callable that when called on a
-      bytestring returns the response value corresponding to
-      that bytestring.
-
-  Returns:
-    An interfaces.RpcMethodInvocationDescription constructed from the given
-      arguments representing a unary-request/streaming-response RPC method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.UNARY_STREAM, None, None, None, None,
-      request_serializer, None, None, response_deserializer)
-
-
-def stream_unary_invocation_description(
-    request_serializer, response_deserializer):
-  """Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
-
-  Args:
-    request_serializer: A callable that when called on a request
-      value returns a bytestring corresponding to that value.
-    response_deserializer: A callable that when called on a
-      bytestring returns the response value corresponding to
-      that bytestring.
-
-  Returns:
-    An interfaces.RpcMethodInvocationDescription constructed from the given
-      arguments representing a streaming-request/unary-response RPC method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.STREAM_UNARY, None, None, None, None,
-      request_serializer, None, None, response_deserializer)
-
-
-def stream_stream_invocation_description(
-    request_serializer, response_deserializer):
-  """Creates an interfaces.RpcMethodInvocationDescription for an RPC method.
-
-  Args:
-    request_serializer: A callable that when called on a request
-      value returns a bytestring corresponding to that value.
-    response_deserializer: A callable that when called on a
-      bytestring returns the response value corresponding to
-      that bytestring.
-
-  Returns:
-    An interfaces.RpcMethodInvocationDescription constructed from the given
-      arguments representing a  streaming-request/streaming-response RPC
-      method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.STREAM_STREAM, None, None, None, None,
-      request_serializer, None, None, response_deserializer)
-
-
-def unary_unary_service_description(
-    behavior, request_deserializer, response_serializer):
-  """Creates an interfaces.RpcMethodServiceDescription for the given behavior.
-
-  Args:
-    behavior: A callable that implements a unary-unary RPC
-      method that accepts a single request and an interfaces.RpcContext and
-      returns a single response.
-    request_deserializer: A callable that when called on a
-      bytestring returns the request value corresponding to that
-      bytestring.
-    response_serializer: A callable that when called on a
-      response value returns the bytestring corresponding to
-      that value.
-
-  Returns:
-    An interfaces.RpcMethodServiceDescription constructed from the given
-      arguments representing a unary-request/unary-response RPC
-      method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.UNARY_UNARY, behavior, None, None, None,
-      None, request_deserializer, response_serializer, None)
-
-
-def unary_stream_service_description(
-    behavior, request_deserializer, response_serializer):
-  """Creates an interfaces.RpcMethodServiceDescription for the given behavior.
-
-  Args:
-    behavior: A callable that implements a unary-stream RPC
-      method that accepts a single request and an interfaces.RpcContext
-      and returns an iterator of zero or more responses.
-    request_deserializer: A callable that when called on a
-      bytestring returns the request value corresponding to that
-      bytestring.
-    response_serializer: A callable that when called on a
-      response value returns the bytestring corresponding to
-      that value.
-
-  Returns:
-    An interfaces.RpcMethodServiceDescription constructed from the given
-      arguments representing a unary-request/streaming-response
-      RPC method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.UNARY_STREAM, None, behavior, None, None,
-      None, request_deserializer, response_serializer, None)
-
-
-def stream_unary_service_description(
-    behavior, request_deserializer, response_serializer):
-  """Creates an interfaces.RpcMethodServiceDescription for the given behavior.
-
-  Args:
-    behavior: A callable that implements a stream-unary RPC
-      method that accepts an iterator of zero or more requests
-      and an interfaces.RpcContext and returns a single response.
-    request_deserializer: A callable that when called on a
-      bytestring returns the request value corresponding to that
-      bytestring.
-    response_serializer: A callable that when called on a
-      response value returns the bytestring corresponding to
-      that value.
-
-  Returns:
-    An interfaces.RpcMethodServiceDescription constructed from the given
-      arguments representing a streaming-request/unary-response
-      RPC method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.STREAM_UNARY, None, None, behavior, None,
-      None, request_deserializer, response_serializer, None)
-
-
-def stream_stream_service_description(
-    behavior, request_deserializer, response_serializer):
-  """Creates an interfaces.RpcMethodServiceDescription for the given behavior.
-
-  Args:
-    behavior: A callable that implements a stream-stream RPC
-      method that accepts an iterator of zero or more requests
-      and an interfaces.RpcContext and returns an iterator of
-      zero or more responses.
-    request_deserializer: A callable that when called on a
-      bytestring returns the request value corresponding to that
-      bytestring.
-    response_serializer: A callable that when called on a
-      response value returns the bytestring corresponding to
-      that value.
-
-  Returns:
-    An interfaces.RpcMethodServiceDescription constructed from the given
-      arguments representing a
-      streaming-request/streaming-response RPC method.
-  """
-  return _RpcMethodDescription(
-      interfaces.Cardinality.STREAM_STREAM, None, None, None, behavior,
-      None, request_deserializer, response_serializer, None)
diff --git a/src/python/grpcio/grpc/framework/base/__init__.py b/src/python/grpcio/grpc/framework/base/__init__.py
deleted file mode 100644
index bff74be..0000000
--- a/src/python/grpcio/grpc/framework/base/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import warnings
-
-warnings.simplefilter('always', DeprecationWarning)
-warnings.warn('the alpha API (includes this package) is deprecated, '
-              'unmaintained, and no longer tested. Please migrate to the beta '
-              'API.', DeprecationWarning, stacklevel=2)
diff --git a/src/python/grpcio/grpc/framework/base/_cancellation.py b/src/python/grpcio/grpc/framework/base/_cancellation.py
deleted file mode 100644
index ffbc906..0000000
--- a/src/python/grpcio/grpc/framework/base/_cancellation.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for operation cancellation."""
-
-from grpc.framework.base import _interfaces
-from grpc.framework.base import interfaces
-
-
-class CancellationManager(_interfaces.CancellationManager):
-  """An implementation of _interfaces.CancellationManager."""
-
-  def __init__(
-      self, lock, termination_manager, transmission_manager, ingestion_manager,
-      expiration_manager):
-    """Constructor.
-
-    Args:
-      lock: The operation-wide lock.
-      termination_manager: The _interfaces.TerminationManager for the operation.
-      transmission_manager: The _interfaces.TransmissionManager for the
-        operation.
-      ingestion_manager: The _interfaces.IngestionManager for the operation.
-      expiration_manager: The _interfaces.ExpirationManager for the operation.
-    """
-    self._lock = lock
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._ingestion_manager = ingestion_manager
-    self._expiration_manager = expiration_manager
-
-  def cancel(self):
-    """See _interfaces.CancellationManager.cancel for specification."""
-    with self._lock:
-      self._termination_manager.abort(interfaces.Outcome.CANCELLED)
-      self._transmission_manager.abort(interfaces.Outcome.CANCELLED)
-      self._ingestion_manager.abort()
-      self._expiration_manager.abort()
diff --git a/src/python/grpcio/grpc/framework/base/_constants.py b/src/python/grpcio/grpc/framework/base/_constants.py
deleted file mode 100644
index 8fbdc82..0000000
--- a/src/python/grpcio/grpc/framework/base/_constants.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Private constants for the package."""
-
-INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Base) internal error! :-('
diff --git a/src/python/grpcio/grpc/framework/base/_context.py b/src/python/grpcio/grpc/framework/base/_context.py
deleted file mode 100644
index d84871d..0000000
--- a/src/python/grpcio/grpc/framework/base/_context.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for operation context."""
-
-import time
-
-# _interfaces is referenced from specification in this module.
-from grpc.framework.base import interfaces
-from grpc.framework.base import _interfaces  # pylint: disable=unused-import
-
-
-class OperationContext(interfaces.OperationContext):
-  """An implementation of interfaces.OperationContext."""
-
-  def __init__(
-      self, lock, operation_id, local_failure, termination_manager,
-      transmission_manager):
-    """Constructor.
-
-    Args:
-      lock: The operation-wide lock.
-      operation_id: An object identifying the operation.
-      local_failure: Whichever one of interfaces.Outcome.SERVICED_FAILURE or
-        interfaces.Outcome.SERVICER_FAILURE describes local failure of
-        customer code.
-      termination_manager: The _interfaces.TerminationManager for the operation.
-      transmission_manager: The _interfaces.TransmissionManager for the
-        operation.
-    """
-    self._lock = lock
-    self._local_failure = local_failure
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._ingestion_manager = None
-    self._expiration_manager = None
-
-    self.operation_id = operation_id
-
-  def set_ingestion_and_expiration_managers(
-      self, ingestion_manager, expiration_manager):
-    """Sets managers with which this OperationContext cooperates.
-
-    Args:
-      ingestion_manager: The _interfaces.IngestionManager for the operation.
-      expiration_manager: The _interfaces.ExpirationManager for the operation.
-    """
-    self._ingestion_manager = ingestion_manager
-    self._expiration_manager = expiration_manager
-
-  def is_active(self):
-    """See interfaces.OperationContext.is_active for specification."""
-    with self._lock:
-      return self._termination_manager.is_active()
-
-  def add_termination_callback(self, callback):
-    """See interfaces.OperationContext.add_termination_callback."""
-    with self._lock:
-      self._termination_manager.add_callback(callback)
-
-  def time_remaining(self):
-    """See interfaces.OperationContext.time_remaining for specification."""
-    with self._lock:
-      deadline = self._expiration_manager.deadline()
-    return max(0.0, deadline - time.time())
-
-  def fail(self, exception):
-    """See interfaces.OperationContext.fail for specification."""
-    with self._lock:
-      self._termination_manager.abort(self._local_failure)
-      self._transmission_manager.abort(self._local_failure)
-      self._ingestion_manager.abort()
-      self._expiration_manager.abort()
diff --git a/src/python/grpcio/grpc/framework/base/_emission.py b/src/python/grpcio/grpc/framework/base/_emission.py
deleted file mode 100644
index 1829669..0000000
--- a/src/python/grpcio/grpc/framework/base/_emission.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for handling emitted values."""
-
-from grpc.framework.base import interfaces
-from grpc.framework.base import _interfaces
-
-
-class _EmissionManager(_interfaces.EmissionManager):
-  """An implementation of _interfaces.EmissionManager."""
-
-  def __init__(
-      self, lock, failure_outcome, termination_manager, transmission_manager):
-    """Constructor.
-
-    Args:
-      lock: The operation-wide lock.
-      failure_outcome: Whichever one of interfaces.Outcome.SERVICED_FAILURE or
-        interfaces.Outcome.SERVICER_FAILURE describes this object's methods
-        being called inappropriately by customer code.
-      termination_manager: The _interfaces.TerminationManager for the operation.
-      transmission_manager: The _interfaces.TransmissionManager for the
-        operation.
-    """
-    self._lock = lock
-    self._failure_outcome = failure_outcome
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._ingestion_manager = None
-    self._expiration_manager = None
-
-    self._emission_complete = False
-
-  def set_ingestion_manager_and_expiration_manager(
-      self, ingestion_manager, expiration_manager):
-    self._ingestion_manager = ingestion_manager
-    self._expiration_manager = expiration_manager
-
-  def _abort(self):
-    self._termination_manager.abort(self._failure_outcome)
-    self._transmission_manager.abort(self._failure_outcome)
-    self._ingestion_manager.abort()
-    self._expiration_manager.abort()
-
-  def consume(self, value):
-    with self._lock:
-      if self._emission_complete:
-        self._abort()
-      else:
-        self._transmission_manager.inmit(value, False)
-
-  def terminate(self):
-    with self._lock:
-      if not self._emission_complete:
-        self._termination_manager.emission_complete()
-        self._transmission_manager.inmit(None, True)
-        self._emission_complete = True
-
-  def consume_and_terminate(self, value):
-    with self._lock:
-      if self._emission_complete:
-        self._abort()
-      else:
-        self._termination_manager.emission_complete()
-        self._transmission_manager.inmit(value, True)
-        self._emission_complete = True
-
-
-def front_emission_manager(lock, termination_manager, transmission_manager):
-  """Creates an _interfaces.EmissionManager appropriate for front-side use.
-
-  Args:
-    lock: The operation-wide lock.
-    termination_manager: The _interfaces.TerminationManager for the operation.
-    transmission_manager: The _interfaces.TransmissionManager for the operation.
-
-  Returns:
-    An _interfaces.EmissionManager appropriate for front-side use.
-  """
-  return _EmissionManager(
-      lock, interfaces.Outcome.SERVICED_FAILURE, termination_manager,
-      transmission_manager)
-
-
-def back_emission_manager(lock, termination_manager, transmission_manager):
-  """Creates an _interfaces.EmissionManager appropriate for back-side use.
-
-  Args:
-    lock: The operation-wide lock.
-    termination_manager: The _interfaces.TerminationManager for the operation.
-    transmission_manager: The _interfaces.TransmissionManager for the operation.
-
-  Returns:
-    An _interfaces.EmissionManager appropriate for back-side use.
-  """
-  return _EmissionManager(
-      lock, interfaces.Outcome.SERVICER_FAILURE, termination_manager,
-      transmission_manager)
diff --git a/src/python/grpcio/grpc/framework/base/_ends.py b/src/python/grpcio/grpc/framework/base/_ends.py
deleted file mode 100644
index 176f3ac..0000000
--- a/src/python/grpcio/grpc/framework/base/_ends.py
+++ /dev/null
@@ -1,399 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Implementations of FrontLinks and BackLinks."""
-
-import collections
-import threading
-import uuid
-
-# _interfaces is referenced from specification in this module.
-from grpc.framework.base import _cancellation
-from grpc.framework.base import _context
-from grpc.framework.base import _emission
-from grpc.framework.base import _expiration
-from grpc.framework.base import _ingestion
-from grpc.framework.base import _interfaces  # pylint: disable=unused-import
-from grpc.framework.base import _reception
-from grpc.framework.base import _termination
-from grpc.framework.base import _transmission
-from grpc.framework.base import interfaces
-from grpc.framework.foundation import callable_util
-
-_IDLE_ACTION_EXCEPTION_LOG_MESSAGE = 'Exception calling idle action!'
-
-
-class _EasyOperation(interfaces.Operation):
-  """A trivial implementation of interfaces.Operation."""
-
-  def __init__(self, emission_manager, context, cancellation_manager):
-    """Constructor.
-
-    Args:
-      emission_manager: The _interfaces.EmissionManager for the operation that
-        will accept values emitted by customer code.
-      context: The interfaces.OperationContext for use by the customer
-        during the operation.
-      cancellation_manager: The _interfaces.CancellationManager for the
-        operation.
-    """
-    self.consumer = emission_manager
-    self.context = context
-    self._cancellation_manager = cancellation_manager
-
-  def cancel(self):
-    self._cancellation_manager.cancel()
-
-
-class _Endlette(object):
-  """Utility for stateful behavior common to Fronts and Backs."""
-
-  def __init__(self, pool):
-    """Constructor.
-
-    Args:
-      pool: A thread pool to use when calling registered idle actions.
-    """
-    self._lock = threading.Lock()
-    self._pool = pool
-    # Dictionary from operation IDs to ReceptionManager-or-None. A None value
-    # indicates an in-progress fire-and-forget operation for which the customer
-    # has chosen to ignore results.
-    self._operations = {}
-    self._stats = {outcome: 0 for outcome in interfaces.Outcome}
-    self._idle_actions = []
-
-  def terminal_action(self, operation_id):
-    """Constructs the termination action for a single operation.
-
-    Args:
-      operation_id: An operation ID.
-
-    Returns:
-      A callable that takes an operation outcome for an argument to be used as
-        the termination action for the operation associated with the given
-        operation ID.
-    """
-    def termination_action(outcome):
-      with self._lock:
-        self._stats[outcome] += 1
-        self._operations.pop(operation_id, None)
-        if not self._operations:
-          for action in self._idle_actions:
-            self._pool.submit(callable_util.with_exceptions_logged(
-                action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE))
-          self._idle_actions = []
-    return termination_action
-
-  def __enter__(self):
-    self._lock.acquire()
-
-  def __exit__(self, exc_type, exc_val, exc_tb):
-    self._lock.release()
-
-  def get_operation(self, operation_id):
-    return self._operations.get(operation_id, None)
-
-  def add_operation(self, operation_id, operation_reception_manager):
-    self._operations[operation_id] = operation_reception_manager
-
-  def operation_stats(self):
-    with self._lock:
-      return dict(self._stats)
-
-  def add_idle_action(self, action):
-    with self._lock:
-      if self._operations:
-        self._idle_actions.append(action)
-      else:
-        self._pool.submit(callable_util.with_exceptions_logged(
-            action, _IDLE_ACTION_EXCEPTION_LOG_MESSAGE))
-
-
-class _FrontManagement(
-    collections.namedtuple(
-        '_FrontManagement',
-        ('reception', 'emission', 'operation', 'cancellation'))):
-  """Just a trivial helper class to bundle four fellow-traveling objects."""
-
-
-def _front_operate(
-    callback, work_pool, transmission_pool, utility_pool,
-    termination_action, operation_id, name, payload, complete, timeout,
-    subscription, trace_id):
-  """Constructs objects necessary for front-side operation management.
-
-  Args:
-    callback: A callable that accepts interfaces.FrontToBackTickets and
-      delivers them to the other side of the operation. Execution of this
-      callable may take any arbitrary length of time.
-    work_pool: A thread pool in which to execute customer code.
-    transmission_pool: A thread pool to use for transmitting to the other side
-      of the operation.
-    utility_pool: A thread pool for utility tasks.
-    termination_action: A no-arg behavior to be called upon operation
-      completion.
-    operation_id: An object identifying the operation.
-    name: The name of the method being called during the operation.
-    payload: The first customer-significant value to be transmitted to the other
-      side. May be None if there is no such value or if the customer chose not
-      to pass it at operation invocation.
-    complete: A boolean indicating whether or not additional payloads will be
-      supplied by the customer.
-    timeout: A length of time in seconds to allow for the operation.
-    subscription: A interfaces.ServicedSubscription describing the
-      customer's interest in the results of the operation.
-    trace_id: A uuid.UUID identifying a set of related operations to which this
-      operation belongs. May be None.
-
-  Returns:
-    A _FrontManagement object bundling together the
-      _interfaces.ReceptionManager, _interfaces.EmissionManager,
-      _context.OperationContext, and _interfaces.CancellationManager for the
-      operation.
-  """
-  lock = threading.Lock()
-  with lock:
-    termination_manager = _termination.front_termination_manager(
-        work_pool, utility_pool, termination_action, subscription.kind)
-    transmission_manager = _transmission.front_transmission_manager(
-        lock, transmission_pool, callback, operation_id, name,
-        subscription.kind, trace_id, timeout, termination_manager)
-    operation_context = _context.OperationContext(
-        lock, operation_id, interfaces.Outcome.SERVICED_FAILURE,
-        termination_manager, transmission_manager)
-    emission_manager = _emission.front_emission_manager(
-        lock, termination_manager, transmission_manager)
-    ingestion_manager = _ingestion.front_ingestion_manager(
-        lock, work_pool, subscription, termination_manager,
-        transmission_manager, operation_context)
-    expiration_manager = _expiration.front_expiration_manager(
-        lock, termination_manager, transmission_manager, ingestion_manager,
-        timeout)
-    reception_manager = _reception.front_reception_manager(
-        lock, termination_manager, transmission_manager, ingestion_manager,
-        expiration_manager)
-    cancellation_manager = _cancellation.CancellationManager(
-        lock, termination_manager, transmission_manager, ingestion_manager,
-        expiration_manager)
-
-    termination_manager.set_expiration_manager(expiration_manager)
-    transmission_manager.set_ingestion_and_expiration_managers(
-        ingestion_manager, expiration_manager)
-    operation_context.set_ingestion_and_expiration_managers(
-        ingestion_manager, expiration_manager)
-    emission_manager.set_ingestion_manager_and_expiration_manager(
-        ingestion_manager, expiration_manager)
-    ingestion_manager.set_expiration_manager(expiration_manager)
-
-    transmission_manager.inmit(payload, complete)
-
-    if subscription.kind is interfaces.ServicedSubscription.Kind.NONE:
-      returned_reception_manager = None
-    else:
-      returned_reception_manager = reception_manager
-
-    return _FrontManagement(
-        returned_reception_manager, emission_manager, operation_context,
-        cancellation_manager)
-
-
-class FrontLink(interfaces.FrontLink):
-  """An implementation of interfaces.FrontLink."""
-
-  def __init__(self, work_pool, transmission_pool, utility_pool):
-    """Constructor.
-
-    Args:
-      work_pool: A thread pool to be used for executing customer code.
-      transmission_pool: A thread pool to be used for transmitting values to
-        the other side of the operation.
-      utility_pool: A thread pool to be used for utility tasks.
-    """
-    self._endlette = _Endlette(utility_pool)
-    self._work_pool = work_pool
-    self._transmission_pool = transmission_pool
-    self._utility_pool = utility_pool
-    self._callback = None
-
-    self._operations = {}
-
-  def join_rear_link(self, rear_link):
-    """See interfaces.ForeLink.join_rear_link for specification."""
-    with self._endlette:
-      self._callback = rear_link.accept_front_to_back_ticket
-
-  def operation_stats(self):
-    """See interfaces.End.operation_stats for specification."""
-    return self._endlette.operation_stats()
-
-  def add_idle_action(self, action):
-    """See interfaces.End.add_idle_action for specification."""
-    self._endlette.add_idle_action(action)
-
-  def operate(
-      self, name, payload, complete, timeout, subscription, trace_id):
-    """See interfaces.Front.operate for specification."""
-    operation_id = uuid.uuid4()
-    with self._endlette:
-      management = _front_operate(
-          self._callback, self._work_pool, self._transmission_pool,
-          self._utility_pool, self._endlette.terminal_action(operation_id),
-          operation_id, name, payload, complete, timeout, subscription,
-          trace_id)
-      self._endlette.add_operation(operation_id, management.reception)
-      return _EasyOperation(
-          management.emission, management.operation, management.cancellation)
-
-  def accept_back_to_front_ticket(self, ticket):
-    """See interfaces.End.act for specification."""
-    with self._endlette:
-      reception_manager = self._endlette.get_operation(ticket.operation_id)
-    if reception_manager:
-      reception_manager.receive_ticket(ticket)
-
-
-def _back_operate(
-    servicer, callback, work_pool, transmission_pool, utility_pool,
-    termination_action, ticket, default_timeout, maximum_timeout):
-  """Constructs objects necessary for back-side operation management.
-
-  Also begins back-side operation by feeding the first received ticket into the
-  constructed _interfaces.ReceptionManager.
-
-  Args:
-    servicer: An interfaces.Servicer for servicing operations.
-    callback: A callable that accepts interfaces.BackToFrontTickets and
-      delivers them to the other side of the operation. Execution of this
-      callable may take any arbitrary length of time.
-    work_pool: A thread pool in which to execute customer code.
-    transmission_pool: A thread pool to use for transmitting to the other side
-      of the operation.
-    utility_pool: A thread pool for utility tasks.
-    termination_action: A no-arg behavior to be called upon operation
-      completion.
-    ticket: The first interfaces.FrontToBackTicket received for the operation.
-    default_timeout: A length of time in seconds to be used as the default
-      time alloted for a single operation.
-    maximum_timeout: A length of time in seconds to be used as the maximum
-      time alloted for a single operation.
-
-  Returns:
-    The _interfaces.ReceptionManager to be used for the operation.
-  """
-  lock = threading.Lock()
-  with lock:
-    termination_manager = _termination.back_termination_manager(
-        work_pool, utility_pool, termination_action, ticket.subscription)
-    transmission_manager = _transmission.back_transmission_manager(
-        lock, transmission_pool, callback, ticket.operation_id,
-        termination_manager, ticket.subscription)
-    operation_context = _context.OperationContext(
-        lock, ticket.operation_id, interfaces.Outcome.SERVICER_FAILURE,
-        termination_manager, transmission_manager)
-    emission_manager = _emission.back_emission_manager(
-        lock, termination_manager, transmission_manager)
-    ingestion_manager = _ingestion.back_ingestion_manager(
-        lock, work_pool, servicer, termination_manager,
-        transmission_manager, operation_context, emission_manager)
-    expiration_manager = _expiration.back_expiration_manager(
-        lock, termination_manager, transmission_manager, ingestion_manager,
-        ticket.timeout, default_timeout, maximum_timeout)
-    reception_manager = _reception.back_reception_manager(
-        lock, termination_manager, transmission_manager, ingestion_manager,
-        expiration_manager)
-
-    termination_manager.set_expiration_manager(expiration_manager)
-    transmission_manager.set_ingestion_and_expiration_managers(
-        ingestion_manager, expiration_manager)
-    operation_context.set_ingestion_and_expiration_managers(
-        ingestion_manager, expiration_manager)
-    emission_manager.set_ingestion_manager_and_expiration_manager(
-        ingestion_manager, expiration_manager)
-    ingestion_manager.set_expiration_manager(expiration_manager)
-
-  reception_manager.receive_ticket(ticket)
-
-  return reception_manager
-
-
-class BackLink(interfaces.BackLink):
-  """An implementation of interfaces.BackLink."""
-
-  def __init__(
-      self, servicer, work_pool, transmission_pool, utility_pool,
-      default_timeout, maximum_timeout):
-    """Constructor.
-
-    Args:
-      servicer: An interfaces.Servicer for servicing operations.
-      work_pool: A thread pool in which to execute customer code.
-      transmission_pool: A thread pool to use for transmitting to the other side
-        of the operation.
-      utility_pool: A thread pool for utility tasks.
-      default_timeout: A length of time in seconds to be used as the default
-        time alloted for a single operation.
-      maximum_timeout: A length of time in seconds to be used as the maximum
-        time alloted for a single operation.
-    """
-    self._endlette = _Endlette(utility_pool)
-    self._servicer = servicer
-    self._work_pool = work_pool
-    self._transmission_pool = transmission_pool
-    self._utility_pool = utility_pool
-    self._default_timeout = default_timeout
-    self._maximum_timeout = maximum_timeout
-    self._callback = None
-
-  def join_fore_link(self, fore_link):
-    """See interfaces.RearLink.join_fore_link for specification."""
-    with self._endlette:
-      self._callback = fore_link.accept_back_to_front_ticket
-
-  def accept_front_to_back_ticket(self, ticket):
-    """See interfaces.RearLink.accept_front_to_back_ticket for specification."""
-    with self._endlette:
-      reception_manager = self._endlette.get_operation(ticket.operation_id)
-      if reception_manager is None:
-        reception_manager = _back_operate(
-            self._servicer, self._callback, self._work_pool,
-            self._transmission_pool, self._utility_pool,
-            self._endlette.terminal_action(ticket.operation_id), ticket,
-            self._default_timeout, self._maximum_timeout)
-        self._endlette.add_operation(ticket.operation_id, reception_manager)
-      else:
-        reception_manager.receive_ticket(ticket)
-
-  def operation_stats(self):
-    """See interfaces.End.operation_stats for specification."""
-    return self._endlette.operation_stats()
-
-  def add_idle_action(self, action):
-    """See interfaces.End.add_idle_action for specification."""
-    self._endlette.add_idle_action(action)
diff --git a/src/python/grpcio/grpc/framework/base/_expiration.py b/src/python/grpcio/grpc/framework/base/_expiration.py
deleted file mode 100644
index 17acbef..0000000
--- a/src/python/grpcio/grpc/framework/base/_expiration.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for operation expiration."""
-
-import time
-
-from grpc.framework.base import _interfaces
-from grpc.framework.base import interfaces
-from grpc.framework.foundation import later
-
-
-class _ExpirationManager(_interfaces.ExpirationManager):
-  """An implementation of _interfaces.ExpirationManager."""
-
-  def __init__(
-      self, lock, termination_manager, transmission_manager, ingestion_manager,
-      commencement, timeout, maximum_timeout):
-    """Constructor.
-
-    Args:
-      lock: The operation-wide lock.
-      termination_manager: The _interfaces.TerminationManager for the operation.
-      transmission_manager: The _interfaces.TransmissionManager for the
-        operation.
-      ingestion_manager: The _interfaces.IngestionManager for the operation.
-      commencement: The time in seconds since the epoch at which the operation
-        began.
-      timeout: A length of time in seconds to allow for the operation to run.
-      maximum_timeout: The maximum length of time in seconds to allow for the
-        operation to run despite what is requested via this object's
-        change_timout method.
-    """
-    self._lock = lock
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._ingestion_manager = ingestion_manager
-    self._commencement = commencement
-    self._maximum_timeout = maximum_timeout
-
-    self._timeout = timeout
-    self._deadline = commencement + timeout
-    self._index = None
-    self._future = None
-
-  def _expire(self, index):
-    with self._lock:
-      if self._future is not None and index == self._index:
-        self._future = None
-        self._termination_manager.abort(interfaces.Outcome.EXPIRED)
-        self._transmission_manager.abort(interfaces.Outcome.EXPIRED)
-        self._ingestion_manager.abort()
-
-  def start(self):
-    self._index = 0
-    self._future = later.later(self._timeout, lambda: self._expire(0))
-
-  def change_timeout(self, timeout):
-    if self._future is not None and timeout != self._timeout:
-      self._future.cancel()
-      new_timeout = min(timeout, self._maximum_timeout)
-      new_index = self._index + 1
-      self._timeout = new_timeout
-      self._deadline = self._commencement + new_timeout
-      self._index = new_index
-      delay = self._deadline - time.time()
-      self._future = later.later(
-          delay, lambda: self._expire(new_index))
-
-  def deadline(self):
-    return self._deadline
-
-  def abort(self):
-    if self._future:
-      self._future.cancel()
-      self._future = None
-    self._deadline_index = None
-
-
-def front_expiration_manager(
-    lock, termination_manager, transmission_manager, ingestion_manager,
-    timeout):
-  """Creates an _interfaces.ExpirationManager appropriate for front-side use.
-
-  Args:
-    lock: The operation-wide lock.
-    termination_manager: The _interfaces.TerminationManager for the operation.
-    transmission_manager: The _interfaces.TransmissionManager for the
-      operation.
-    ingestion_manager: The _interfaces.IngestionManager for the operation.
-    timeout: A length of time in seconds to allow for the operation to run.
-
-  Returns:
-    An _interfaces.ExpirationManager appropriate for front-side use.
-  """
-  commencement = time.time()
-  expiration_manager = _ExpirationManager(
-      lock, termination_manager, transmission_manager, ingestion_manager,
-      commencement, timeout, timeout)
-  expiration_manager.start()
-  return expiration_manager
-
-
-def back_expiration_manager(
-    lock, termination_manager, transmission_manager, ingestion_manager,
-    timeout, default_timeout, maximum_timeout):
-  """Creates an _interfaces.ExpirationManager appropriate for back-side use.
-
-  Args:
-    lock: The operation-wide lock.
-    termination_manager: The _interfaces.TerminationManager for the operation.
-    transmission_manager: The _interfaces.TransmissionManager for the
-      operation.
-    ingestion_manager: The _interfaces.IngestionManager for the operation.
-    timeout: A length of time in seconds to allow for the operation to run. May
-      be None in which case default_timeout will be used.
-    default_timeout: The default length of time in seconds to allow for the
-      operation to run if the front-side customer has not specified such a value
-      (or if the value they specified is not yet known).
-    maximum_timeout: The maximum length of time in seconds to allow for the
-      operation to run.
-
-  Returns:
-    An _interfaces.ExpirationManager appropriate for back-side use.
-  """
-  commencement = time.time()
-  expiration_manager = _ExpirationManager(
-      lock, termination_manager, transmission_manager, ingestion_manager,
-      commencement, default_timeout if timeout is None else timeout,
-      maximum_timeout)
-  expiration_manager.start()
-  return expiration_manager
diff --git a/src/python/grpcio/grpc/framework/base/_ingestion.py b/src/python/grpcio/grpc/framework/base/_ingestion.py
deleted file mode 100644
index c9b10ac..0000000
--- a/src/python/grpcio/grpc/framework/base/_ingestion.py
+++ /dev/null
@@ -1,443 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for ingestion during an operation."""
-
-import abc
-import collections
-
-import six
-
-from grpc.framework.base import _constants
-from grpc.framework.base import _interfaces
-from grpc.framework.base import exceptions
-from grpc.framework.base import interfaces
-from grpc.framework.foundation import abandonment
-from grpc.framework.foundation import callable_util
-from grpc.framework.foundation import stream
-
-_CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!'
-_CONSUME_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!'
-
-
-class _ConsumerCreation(collections.namedtuple(
-    '_ConsumerCreation', ('consumer', 'remote_error', 'abandoned'))):
-  """A sum type for the outcome of ingestion initialization.
-
-  Either consumer will be non-None, remote_error will be True, or abandoned will
-  be True.
-
-  Attributes:
-    consumer: A stream.Consumer for ingesting payloads.
-    remote_error: A boolean indicating that the consumer could not be created
-      due to an error on the remote side of the operation.
-    abandoned: A boolean indicating that the consumer creation was abandoned.
-  """
-
-
-class _EmptyConsumer(stream.Consumer):
-  """A no-operative stream.Consumer that ignores all inputs and calls."""
-
-  def consume(self, value):
-    """See stream.Consumer.consume for specification."""
-
-  def terminate(self):
-    """See stream.Consumer.terminate for specification."""
-
-  def consume_and_terminate(self, value):
-    """See stream.Consumer.consume_and_terminate for specification."""
-
-
-class _ConsumerCreator(six.with_metaclass(abc.ABCMeta)):
-  """Common specification of different consumer-creating behavior."""
-
-  @abc.abstractmethod
-  def create_consumer(self, requirement):
-    """Creates the stream.Consumer to which customer payloads will be delivered.
-
-    Any exceptions raised by this method should be attributed to and treated as
-    defects in the serviced or servicer code called by this method.
-
-    Args:
-      requirement: A value required by this _ConsumerCreator for consumer
-        creation.
-
-    Returns:
-      A _ConsumerCreation describing the result of consumer creation.
-    """
-    raise NotImplementedError()
-
-
-class _FrontConsumerCreator(_ConsumerCreator):
-  """A _ConsumerCreator appropriate for front-side use."""
-
-  def __init__(self, subscription, operation_context):
-    """Constructor.
-
-    Args:
-      subscription: The serviced's interfaces.ServicedSubscription for the
-        operation.
-      operation_context: The interfaces.OperationContext object for the
-        operation.
-    """
-    self._subscription = subscription
-    self._operation_context = operation_context
-
-  def create_consumer(self, requirement):
-    """See _ConsumerCreator.create_consumer for specification."""
-    if self._subscription.kind is interfaces.ServicedSubscription.Kind.FULL:
-      try:
-        return _ConsumerCreation(
-            self._subscription.ingestor.consumer(self._operation_context),
-            False, False)
-      except abandonment.Abandoned:
-        return _ConsumerCreation(None, False, True)
-    else:
-      return _ConsumerCreation(_EmptyConsumer(), False, False)
-
-
-class _BackConsumerCreator(_ConsumerCreator):
-  """A _ConsumerCreator appropriate for back-side use."""
-
-  def __init__(self, servicer, operation_context, emission_consumer):
-    """Constructor.
-
-    Args:
-      servicer: The interfaces.Servicer that will service the operation.
-      operation_context: The interfaces.OperationContext object for the
-        operation.
-      emission_consumer: The stream.Consumer object to which payloads emitted
-        from the operation will be passed.
-    """
-    self._servicer = servicer
-    self._operation_context = operation_context
-    self._emission_consumer = emission_consumer
-
-  def create_consumer(self, requirement):
-    """See _ConsumerCreator.create_consumer for full specification.
-
-    Args:
-      requirement: The name of the Servicer method to be called during this
-        operation.
-
-    Returns:
-      A _ConsumerCreation describing the result of consumer creation.
-    """
-    try:
-      return _ConsumerCreation(
-          self._servicer.service(
-              requirement, self._operation_context, self._emission_consumer),
-          False, False)
-    except exceptions.NoSuchMethodError:
-      return _ConsumerCreation(None, True, False)
-    except abandonment.Abandoned:
-      return _ConsumerCreation(None, False, True)
-
-
-class _WrappedConsumer(object):
-  """Wraps a consumer to catch the exceptions that it is allowed to throw."""
-
-  def __init__(self, consumer):
-    """Constructor.
-
-    Args:
-      consumer: A stream.Consumer that may raise abandonment.Abandoned from any
-        of its methods.
-    """
-    self._consumer = consumer
-
-  def moar(self, payload, complete):
-    """Makes progress with the wrapped consumer.
-
-    This method catches all exceptions allowed to be thrown by the wrapped
-    consumer. Any exceptions raised by this method should be blamed on the
-    customer-supplied consumer.
-
-    Args:
-      payload: A customer-significant payload object. May be None only if
-        complete is True.
-      complete: Whether or not the end of the payload sequence has been reached.
-        Must be True if payload is None.
-
-    Returns:
-      True if the wrapped consumer made progress or False if the wrapped
-        consumer raised abandonment.Abandoned to indicate its abandonment of
-        progress.
-    """
-    try:
-      if payload is None:
-        self._consumer.terminate()
-      elif complete:
-        self._consumer.consume_and_terminate(payload)
-      else:
-        self._consumer.consume(payload)
-      return True
-    except abandonment.Abandoned:
-      return False
-
-
-class _IngestionManager(_interfaces.IngestionManager):
-  """An implementation of _interfaces.IngestionManager."""
-
-  def __init__(
-      self, lock, pool, consumer_creator, failure_outcome, termination_manager,
-      transmission_manager):
-    """Constructor.
-
-    Args:
-      lock: The operation-wide lock.
-      pool: A thread pool in which to execute customer code.
-      consumer_creator: A _ConsumerCreator wrapping the portion of customer code
-        that when called returns the stream.Consumer with which the customer
-        code will ingest payload values.
-      failure_outcome: Whichever one of
-        interfaces.Outcome.SERVICED_FAILURE or
-        interfaces.Outcome.SERVICER_FAILURE describes local failure of
-        customer code.
-      termination_manager: The _interfaces.TerminationManager for the operation.
-      transmission_manager: The _interfaces.TransmissionManager for the
-        operation.
-    """
-    self._lock = lock
-    self._pool = pool
-    self._consumer_creator = consumer_creator
-    self._failure_outcome = failure_outcome
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._expiration_manager = None
-
-    self._wrapped_ingestion_consumer = None
-    self._pending_ingestion = []
-    self._ingestion_complete = False
-    self._processing = False
-
-  def set_expiration_manager(self, expiration_manager):
-    self._expiration_manager = expiration_manager
-
-  def _abort_internal_only(self):
-    self._wrapped_ingestion_consumer = None
-    self._pending_ingestion = None
-
-  def _abort_and_notify(self, outcome):
-    self._abort_internal_only()
-    self._termination_manager.abort(outcome)
-    self._transmission_manager.abort(outcome)
-    self._expiration_manager.abort()
-
-  def _next(self):
-    """Computes the next step for ingestion.
-
-    Returns:
-      A payload, complete, continue triplet indicating what payload (if any) is
-        available to feed into customer code, whether or not the sequence of
-        payloads has terminated, and whether or not there is anything
-        immediately actionable to call customer code to do.
-    """
-    if self._pending_ingestion is None:
-      return None, False, False
-    elif self._pending_ingestion:
-      payload = self._pending_ingestion.pop(0)
-      complete = self._ingestion_complete and not self._pending_ingestion
-      return payload, complete, True
-    elif self._ingestion_complete:
-      return None, True, True
-    else:
-      return None, False, False
-
-  def _process(self, wrapped_ingestion_consumer, payload, complete):
-    """A method to call to execute customer code.
-
-    This object's lock must *not* be held when calling this method.
-
-    Args:
-      wrapped_ingestion_consumer: The _WrappedConsumer with which to pass
-        payloads to customer code.
-      payload: A customer payload. May be None only if complete is True.
-      complete: Whether or not the sequence of payloads to pass to the customer
-        has concluded.
-    """
-    while True:
-      consumption_outcome = callable_util.call_logging_exceptions(
-          wrapped_ingestion_consumer.moar, _CONSUME_EXCEPTION_LOG_MESSAGE,
-          payload, complete)
-      if consumption_outcome.exception is None:
-        if consumption_outcome.return_value:
-          with self._lock:
-            if complete:
-              self._pending_ingestion = None
-              self._termination_manager.ingestion_complete()
-              return
-            else:
-              payload, complete, moar = self._next()
-              if not moar:
-                self._processing = False
-                return
-        else:
-          with self._lock:
-            if self._pending_ingestion is not None:
-              self._abort_and_notify(self._failure_outcome)
-            self._processing = False
-            return
-      else:
-        with self._lock:
-          self._abort_and_notify(self._failure_outcome)
-          self._processing = False
-          return
-
-  def start(self, requirement):
-    if self._pending_ingestion is not None:
-      def initialize():
-        consumer_creation_outcome = callable_util.call_logging_exceptions(
-            self._consumer_creator.create_consumer,
-            _CREATE_CONSUMER_EXCEPTION_LOG_MESSAGE, requirement)
-        if consumer_creation_outcome.return_value is None:
-          with self._lock:
-            self._abort_and_notify(self._failure_outcome)
-            self._processing = False
-        elif consumer_creation_outcome.return_value.remote_error:
-          with self._lock:
-            self._abort_and_notify(interfaces.Outcome.RECEPTION_FAILURE)
-            self._processing = False
-        elif consumer_creation_outcome.return_value.abandoned:
-          with self._lock:
-            if self._pending_ingestion is not None:
-              self._abort_and_notify(self._failure_outcome)
-            self._processing = False
-        else:
-          wrapped_ingestion_consumer = _WrappedConsumer(
-              consumer_creation_outcome.return_value.consumer)
-          with self._lock:
-            self._wrapped_ingestion_consumer = wrapped_ingestion_consumer
-            payload, complete, moar = self._next()
-            if not moar:
-              self._processing = False
-              return
-
-          self._process(wrapped_ingestion_consumer, payload, complete)
-
-      self._pool.submit(
-          callable_util.with_exceptions_logged(
-              initialize, _constants.INTERNAL_ERROR_LOG_MESSAGE))
-      self._processing = True
-
-  def consume(self, payload):
-    if self._ingestion_complete:
-      self._abort_and_notify(self._failure_outcome)
-    elif self._pending_ingestion is not None:
-      if self._processing:
-        self._pending_ingestion.append(payload)
-      else:
-        self._pool.submit(
-            callable_util.with_exceptions_logged(
-                self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE),
-            self._wrapped_ingestion_consumer, payload, False)
-        self._processing = True
-
-  def terminate(self):
-    if self._ingestion_complete:
-      self._abort_and_notify(self._failure_outcome)
-    else:
-      self._ingestion_complete = True
-      if self._pending_ingestion is not None and not self._processing:
-        self._pool.submit(
-            callable_util.with_exceptions_logged(
-                self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE),
-            self._wrapped_ingestion_consumer, None, True)
-        self._processing = True
-
-  def consume_and_terminate(self, payload):
-    if self._ingestion_complete:
-      self._abort_and_notify(self._failure_outcome)
-    else:
-      self._ingestion_complete = True
-      if self._pending_ingestion is not None:
-        if self._processing:
-          self._pending_ingestion.append(payload)
-        else:
-          self._pool.submit(
-              callable_util.with_exceptions_logged(
-                  self._process, _constants.INTERNAL_ERROR_LOG_MESSAGE),
-              self._wrapped_ingestion_consumer, payload, True)
-          self._processing = True
-
-  def abort(self):
-    """See _interfaces.IngestionManager.abort for specification."""
-    self._abort_internal_only()
-
-
-def front_ingestion_manager(
-    lock, pool, subscription, termination_manager, transmission_manager,
-    operation_context):
-  """Creates an IngestionManager appropriate for front-side use.
-
-  Args:
-    lock: The operation-wide lock.
-    pool: A thread pool in which to execute customer code.
-    subscription: A interfaces.ServicedSubscription indicating the
-      customer's interest in the results of the operation.
-    termination_manager: The _interfaces.TerminationManager for the operation.
-    transmission_manager: The _interfaces.TransmissionManager for the
-      operation.
-    operation_context: A interfaces.OperationContext for the operation.
-
-  Returns:
-    An IngestionManager appropriate for front-side use.
-  """
-  ingestion_manager = _IngestionManager(
-      lock, pool, _FrontConsumerCreator(subscription, operation_context),
-      interfaces.Outcome.SERVICED_FAILURE, termination_manager,
-      transmission_manager)
-  ingestion_manager.start(None)
-  return ingestion_manager
-
-
-def back_ingestion_manager(
-    lock, pool, servicer, termination_manager, transmission_manager,
-    operation_context, emission_consumer):
-  """Creates an IngestionManager appropriate for back-side use.
-
-  Args:
-    lock: The operation-wide lock.
-    pool: A thread pool in which to execute customer code.
-    servicer: A interfaces.Servicer for servicing the operation.
-    termination_manager: The _interfaces.TerminationManager for the operation.
-    transmission_manager: The _interfaces.TransmissionManager for the
-      operation.
-    operation_context: A interfaces.OperationContext for the operation.
-    emission_consumer: The _interfaces.EmissionConsumer for the operation.
-
-  Returns:
-    An IngestionManager appropriate for back-side use.
-  """
-  ingestion_manager = _IngestionManager(
-      lock, pool, _BackConsumerCreator(
-          servicer, operation_context, emission_consumer),
-      interfaces.Outcome.SERVICER_FAILURE, termination_manager,
-      transmission_manager)
-  return ingestion_manager
diff --git a/src/python/grpcio/grpc/framework/base/_interfaces.py b/src/python/grpcio/grpc/framework/base/_interfaces.py
deleted file mode 100644
index 6bb9837..0000000
--- a/src/python/grpcio/grpc/framework/base/_interfaces.py
+++ /dev/null
@@ -1,266 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Package-internal interfaces."""
-
-import abc
-
-import six
-
-# interfaces is referenced from specification in this module.
-from grpc.framework.base import interfaces  # pylint: disable=unused-import
-from grpc.framework.foundation import stream
-
-
-class TerminationManager(six.with_metaclass(abc.ABCMeta)):
-  """An object responsible for handling the termination of an operation."""
-
-  @abc.abstractmethod
-  def set_expiration_manager(self, expiration_manager):
-    """Sets the ExpirationManager with which this object will cooperate."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def is_active(self):
-    """Reports whether or not the operation is active.
-
-    Returns:
-      True if the operation is active or False if the operation has terminated.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def add_callback(self, callback):
-    """Registers a callback to be called on operation termination.
-
-    If the operation has already terminated, the callback will be called
-    immediately.
-
-    Args:
-      callback: A callable that will be passed an interfaces.Outcome value.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def emission_complete(self):
-    """Indicates that emissions from customer code have completed."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def transmission_complete(self):
-    """Indicates that transmissions to the remote end are complete."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def ingestion_complete(self):
-    """Indicates that customer code ingestion of received values is complete."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def abort(self, outcome):
-    """Indicates that the operation must abort for the indicated reason.
-
-    Args:
-      outcome: An interfaces.Outcome indicating operation abortion.
-    """
-    raise NotImplementedError()
-
-
-class TransmissionManager(six.with_metaclass(abc.ABCMeta)):
-  """A manager responsible for transmitting to the other end of an operation."""
-
-  @abc.abstractmethod
-  def inmit(self, emission, complete):
-    """Accepts a value for transmission to the other end of the operation.
-
-    Args:
-      emission: A value of some significance to the customer to be transmitted
-        to the other end of the operation. May be None only if complete is True.
-      complete: A boolean that if True indicates that customer code has emitted
-        all values it intends to emit.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def abort(self, outcome):
-    """Indicates that the operation has aborted for the indicated reason.
-
-    Args:
-      outcome: An interfaces.Outcome indicating operation abortion.
-    """
-    raise NotImplementedError()
-
-
-class EmissionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)):
-  """A manager of values emitted by customer code."""
-
-  @abc.abstractmethod
-  def set_ingestion_manager_and_expiration_manager(
-      self, ingestion_manager, expiration_manager):
-    """Sets two other objects with which this EmissionManager will cooperate.
-
-    Args:
-      ingestion_manager: The IngestionManager for the operation.
-      expiration_manager: The ExpirationManager for the operation.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def consume(self, value):
-    """Accepts a value emitted by customer code.
-
-    This method should only be called by customer code.
-
-    Args:
-      value: Any value of significance to the customer.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def terminate(self):
-    """Indicates that no more values will be emitted by customer code.
-
-    This method should only be called by customer code.
-
-    Implementations of this method may be idempotent and forgive customer code
-    calling this method more than once.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def consume_and_terminate(self, value):
-    """Accepts the last value emitted by customer code.
-
-    This method should only be called by customer code.
-
-    Args:
-      value: Any value of significance to the customer.
-    """
-    raise NotImplementedError()
-
-
-class IngestionManager(six.with_metaclass(abc.ABCMeta, stream.Consumer)):
-  """A manager responsible for executing customer code."""
-
-  @abc.abstractmethod
-  def set_expiration_manager(self, expiration_manager):
-    """Sets the ExpirationManager with which this object will cooperate."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def start(self, requirement):
-    """Commences execution of customer code.
-
-    Args:
-      requirement: Some value unavailable at the time of this object's
-        construction that is required to begin executing customer code.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def consume(self, payload):
-    """Accepts a customer-significant value to be supplied to customer code.
-
-    Args:
-      payload: Some customer-significant value.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def terminate(self):
-    """Indicates the end of values to be supplied to customer code."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def consume_and_terminate(self, payload):
-    """Accepts the last value to be supplied to customer code.
-
-    Args:
-      payload: Some customer-significant value (and the last such value).
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def abort(self):
-    """Indicates to this manager that the operation has aborted."""
-    raise NotImplementedError()
-
-
-class ExpirationManager(six.with_metaclass(abc.ABCMeta)):
-  """A manager responsible for aborting the operation if it runs out of time."""
-
-  @abc.abstractmethod
-  def change_timeout(self, timeout):
-    """Changes the timeout allotted for the operation.
-
-    Operation duration is always measure from the beginning of the operation;
-    calling this method changes the operation's allotted time to timeout total
-    seconds, not timeout seconds from the time of this method call.
-
-    Args:
-      timeout: A length of time in seconds to allow for the operation.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def deadline(self):
-    """Returns the time until which the operation is allowed to run.
-
-    Returns:
-      The time (seconds since the epoch) at which the operation will expire.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def abort(self):
-    """Indicates to this manager that the operation has aborted."""
-    raise NotImplementedError()
-
-
-class ReceptionManager(six.with_metaclass(abc.ABCMeta)):
-  """A manager responsible for receiving tickets from the other end."""
-
-  @abc.abstractmethod
-  def receive_ticket(self, ticket):
-    """Handle a ticket from the other side of the operation.
-
-    Args:
-      ticket: An interfaces.BackToFrontTicket or interfaces.FrontToBackTicket
-        appropriate to this end of the operation and this object.
-    """
-    raise NotImplementedError()
-
-
-class CancellationManager(six.with_metaclass(abc.ABCMeta)):
-  """A manager of operation cancellation."""
-
-  @abc.abstractmethod
-  def cancel(self):
-    """Cancels the operation."""
-    raise NotImplementedError()
diff --git a/src/python/grpcio/grpc/framework/base/_reception.py b/src/python/grpcio/grpc/framework/base/_reception.py
deleted file mode 100644
index a59c516..0000000
--- a/src/python/grpcio/grpc/framework/base/_reception.py
+++ /dev/null
@@ -1,400 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for ticket reception."""
-
-import abc
-
-import six
-
-from grpc.framework.base import interfaces
-from grpc.framework.base import _interfaces
-
-_INITIAL_FRONT_TO_BACK_TICKET_KINDS = (
-    interfaces.FrontToBackTicket.Kind.COMMENCEMENT,
-    interfaces.FrontToBackTicket.Kind.ENTIRE,
-)
-
-
-class _Receiver(six.with_metaclass(abc.ABCMeta)):
-  """Common specification of different ticket-handling behavior."""
-
-  @abc.abstractmethod
-  def abort_if_abortive(self, ticket):
-    """Aborts the operation if the ticket is abortive.
-
-    Args:
-      ticket: A just-arrived ticket.
-
-    Returns:
-      A boolean indicating whether or not this Receiver aborted the operation
-        based on the ticket.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def receive(self, ticket):
-    """Handles a just-arrived ticket.
-
-    Args:
-      ticket: A just-arrived ticket.
-
-    Returns:
-      A boolean indicating whether or not the ticket was terminal (i.e. whether
-        or not non-abortive tickets are legal after this one).
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def reception_failure(self):
-    """Aborts the operation with an indication of reception failure."""
-    raise NotImplementedError()
-
-
-def _abort(
-    outcome, termination_manager, transmission_manager, ingestion_manager,
-    expiration_manager):
-  """Indicates abortion with the given outcome to the given managers."""
-  termination_manager.abort(outcome)
-  transmission_manager.abort(outcome)
-  ingestion_manager.abort()
-  expiration_manager.abort()
-
-
-def _abort_if_abortive(
-    ticket, abortive, termination_manager, transmission_manager,
-    ingestion_manager, expiration_manager):
-  """Determines a ticket's being abortive and if so aborts the operation.
-
-  Args:
-    ticket: A just-arrived ticket.
-    abortive: A callable that takes a ticket and returns an interfaces.Outcome
-      indicating that the operation should be aborted or None indicating that
-      the operation should not be aborted.
-    termination_manager: The operation's _interfaces.TerminationManager.
-    transmission_manager: The operation's _interfaces.TransmissionManager.
-    ingestion_manager: The operation's _interfaces.IngestionManager.
-    expiration_manager: The operation's _interfaces.ExpirationManager.
-
-  Returns:
-    True if the operation was aborted; False otherwise.
-  """
-  abortion_outcome = abortive(ticket)
-  if abortion_outcome is None:
-    return False
-  else:
-    _abort(
-        abortion_outcome, termination_manager, transmission_manager,
-        ingestion_manager, expiration_manager)
-    return True
-
-
-def _reception_failure(
-    termination_manager, transmission_manager, ingestion_manager,
-    expiration_manager):
-  """Aborts the operation with an indication of reception failure."""
-  _abort(
-      interfaces.Outcome.RECEPTION_FAILURE, termination_manager,
-      transmission_manager, ingestion_manager, expiration_manager)
-
-
-class _BackReceiver(_Receiver):
-  """Ticket-handling specific to the back side of an operation."""
-
-  def __init__(
-      self, termination_manager, transmission_manager, ingestion_manager,
-      expiration_manager):
-    """Constructor.
-
-    Args:
-      termination_manager: The operation's _interfaces.TerminationManager.
-      transmission_manager: The operation's _interfaces.TransmissionManager.
-      ingestion_manager: The operation's _interfaces.IngestionManager.
-      expiration_manager: The operation's _interfaces.ExpirationManager.
-    """
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._ingestion_manager = ingestion_manager
-    self._expiration_manager = expiration_manager
-
-    self._first_ticket_seen = False
-    self._last_ticket_seen = False
-
-  def _abortive(self, ticket):
-    """Determines whether or not (and if so, how) a ticket is abortive.
-
-    Args:
-      ticket: A just-arrived ticket.
-
-    Returns:
-      An interfaces.Outcome value describing operation abortion if the
-        ticket is abortive or None if the ticket is not abortive.
-    """
-    if ticket.kind is interfaces.FrontToBackTicket.Kind.CANCELLATION:
-      return interfaces.Outcome.CANCELLED
-    elif ticket.kind is interfaces.FrontToBackTicket.Kind.EXPIRATION:
-      return interfaces.Outcome.EXPIRED
-    elif ticket.kind is interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE:
-      return interfaces.Outcome.SERVICED_FAILURE
-    elif ticket.kind is interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE:
-      return interfaces.Outcome.SERVICED_FAILURE
-    elif (ticket.kind in _INITIAL_FRONT_TO_BACK_TICKET_KINDS and
-          self._first_ticket_seen):
-      return interfaces.Outcome.RECEPTION_FAILURE
-    elif self._last_ticket_seen:
-      return interfaces.Outcome.RECEPTION_FAILURE
-    else:
-      return None
-
-  def abort_if_abortive(self, ticket):
-    """See _Receiver.abort_if_abortive for specification."""
-    return _abort_if_abortive(
-        ticket, self._abortive, self._termination_manager,
-        self._transmission_manager, self._ingestion_manager,
-        self._expiration_manager)
-
-  def receive(self, ticket):
-    """See _Receiver.receive for specification."""
-    if ticket.timeout is not None:
-      self._expiration_manager.change_timeout(ticket.timeout)
-
-    if ticket.kind is interfaces.FrontToBackTicket.Kind.COMMENCEMENT:
-      self._first_ticket_seen = True
-      self._ingestion_manager.start(ticket.name)
-      if ticket.payload is not None:
-        self._ingestion_manager.consume(ticket.payload)
-    elif ticket.kind is interfaces.FrontToBackTicket.Kind.CONTINUATION:
-      self._ingestion_manager.consume(ticket.payload)
-    elif ticket.kind is interfaces.FrontToBackTicket.Kind.COMPLETION:
-      self._last_ticket_seen = True
-      if ticket.payload is None:
-        self._ingestion_manager.terminate()
-      else:
-        self._ingestion_manager.consume_and_terminate(ticket.payload)
-    else:
-      self._first_ticket_seen = True
-      self._last_ticket_seen = True
-      self._ingestion_manager.start(ticket.name)
-      if ticket.payload is None:
-        self._ingestion_manager.terminate()
-      else:
-        self._ingestion_manager.consume_and_terminate(ticket.payload)
-
-  def reception_failure(self):
-    """See _Receiver.reception_failure for specification."""
-    _reception_failure(
-        self._termination_manager, self._transmission_manager,
-        self._ingestion_manager, self._expiration_manager)
-
-
-class _FrontReceiver(_Receiver):
-  """Ticket-handling specific to the front side of an operation."""
-
-  def __init__(
-      self, termination_manager, transmission_manager, ingestion_manager,
-      expiration_manager):
-    """Constructor.
-
-    Args:
-      termination_manager: The operation's _interfaces.TerminationManager.
-      transmission_manager: The operation's _interfaces.TransmissionManager.
-      ingestion_manager: The operation's _interfaces.IngestionManager.
-      expiration_manager: The operation's _interfaces.ExpirationManager.
-    """
-    self._termination_manager = termination_manager
-    self._transmission_manager = transmission_manager
-    self._ingestion_manager = ingestion_manager
-    self._expiration_manager = expiration_manager
-
-    self._last_ticket_seen = False
-
-  def _abortive(self, ticket):
-    """Determines whether or not (and if so, how) a ticket is abortive.
-
-    Args:
-      ticket: A just-arrived ticket.
-
-    Returns:
-      An interfaces.Outcome value describing operation abortion if the ticket
-        is abortive or None if the ticket is not abortive.
-    """
-    if ticket.kind is interfaces.BackToFrontTicket.Kind.CANCELLATION:
-      return interfaces.Outcome.CANCELLED
-    elif ticket.kind is interfaces.BackToFrontTicket.Kind.EXPIRATION:
-      return interfaces.Outcome.EXPIRED
-    elif ticket.kind is interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE:
-      return interfaces.Outcome.SERVICER_FAILURE
-    elif ticket.kind is interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE:
-      return interfaces.Outcome.SERVICER_FAILURE
-    elif self._last_ticket_seen:
-      return interfaces.Outcome.RECEPTION_FAILURE
-    else:
-      return None
-
-  def abort_if_abortive(self, ticket):
-    """See _Receiver.abort_if_abortive for specification."""
-    return _abort_if_abortive(
-        ticket, self._abortive, self._termination_manager,
-        self._transmission_manager, self._ingestion_manager,
-        self._expiration_manager)
-
-  def receive(self, ticket):
-    """See _Receiver.receive for specification."""
-    if ticket.kind is interfaces.BackToFrontTicket.Kind.CONTINUATION:
-      self._ingestion_manager.consume(ticket.payload)
-    elif ticket.kind is interfaces.BackToFrontTicket.Kind.COMPLETION:
-      self._last_ticket_seen = True
-      if ticket.payload is None:
-        self._ingestion_manager.terminate()
-      else:
-        self._ingestion_manager.consume_and_terminate(ticket.payload)
-
-  def reception_failure(self):
-    """See _Receiver.reception_failure for specification."""
-    _reception_failure(
-        self._termination_manager, self._transmission_manager,
-        self._ingestion_manager, self._expiration_manager)
-
-
-class _ReceptionManager(_interfaces.ReceptionManager):
-  """A ReceptionManager based around a _Receiver passed to it."""
-
-  def __init__(self, lock, receiver):
-    """Constructor.
-
-    Args:
-      lock: The operation-servicing-wide lock object.
-      receiver: A _Receiver responsible for handling received tickets.
-    """
-    self._lock = lock
-    self._receiver = receiver
-
-    self._lowest_unseen_sequence_number = 0
-    self._out_of_sequence_tickets = {}
-    self._completed_sequence_number = None
-    self._aborted = False
-
-  def _sequence_failure(self, ticket):
-    """Determines a just-arrived ticket's sequential legitimacy.
-
-    Args:
-      ticket: A just-arrived ticket.
-
-    Returns:
-      True if the ticket is sequentially legitimate; False otherwise.
-    """
-    if ticket.sequence_number < self._lowest_unseen_sequence_number:
-      return True
-    elif ticket.sequence_number in self._out_of_sequence_tickets:
-      return True
-    elif (self._completed_sequence_number is not None and
-          self._completed_sequence_number <= ticket.sequence_number):
-      return True
-    else:
-      return False
-
-  def _process(self, ticket):
-    """Process those tickets ready to be processed.
-
-    Args:
-      ticket: A just-arrived ticket the sequence number of which matches this
-        _ReceptionManager's _lowest_unseen_sequence_number field.
-    """
-    while True:
-      completed = self._receiver.receive(ticket)
-      if completed:
-        self._out_of_sequence_tickets.clear()
-        self._completed_sequence_number = ticket.sequence_number
-        self._lowest_unseen_sequence_number = ticket.sequence_number + 1
-        return
-      else:
-        next_ticket = self._out_of_sequence_tickets.pop(
-            ticket.sequence_number + 1, None)
-        if next_ticket is None:
-          self._lowest_unseen_sequence_number = ticket.sequence_number + 1
-          return
-        else:
-          ticket = next_ticket
-
-  def receive_ticket(self, ticket):
-    """See _interfaces.ReceptionManager.receive_ticket for specification."""
-    with self._lock:
-      if self._aborted:
-        return
-      elif self._sequence_failure(ticket):
-        self._receiver.reception_failure()
-        self._aborted = True
-      elif self._receiver.abort_if_abortive(ticket):
-        self._aborted = True
-      elif ticket.sequence_number == self._lowest_unseen_sequence_number:
-        self._process(ticket)
-      else:
-        self._out_of_sequence_tickets[ticket.sequence_number] = ticket
-
-
-def front_reception_manager(
-    lock, termination_manager, transmission_manager, ingestion_manager,
-    expiration_manager):
-  """Creates a _interfaces.ReceptionManager for front-side use.
-
-  Args:
-    lock: The operation-servicing-wide lock object.
-    termination_manager: The operation's _interfaces.TerminationManager.
-    transmission_manager: The operation's _interfaces.TransmissionManager.
-    ingestion_manager: The operation's _interfaces.IngestionManager.
-    expiration_manager: The operation's _interfaces.ExpirationManager.
-
-  Returns:
-    A _interfaces.ReceptionManager appropriate for front-side use.
-  """
-  return _ReceptionManager(
-      lock, _FrontReceiver(
-          termination_manager, transmission_manager, ingestion_manager,
-          expiration_manager))
-
-
-def back_reception_manager(
-    lock, termination_manager, transmission_manager, ingestion_manager,
-    expiration_manager):
-  """Creates a _interfaces.ReceptionManager for back-side use.
-
-  Args:
-    lock: The operation-servicing-wide lock object.
-    termination_manager: The operation's _interfaces.TerminationManager.
-    transmission_manager: The operation's _interfaces.TransmissionManager.
-    ingestion_manager: The operation's _interfaces.IngestionManager.
-    expiration_manager: The operation's _interfaces.ExpirationManager.
-
-  Returns:
-    A _interfaces.ReceptionManager appropriate for back-side use.
-  """
-  return _ReceptionManager(
-      lock, _BackReceiver(
-          termination_manager, transmission_manager, ingestion_manager,
-          expiration_manager))
diff --git a/src/python/grpcio/grpc/framework/base/_termination.py b/src/python/grpcio/grpc/framework/base/_termination.py
deleted file mode 100644
index ddcbc60..0000000
--- a/src/python/grpcio/grpc/framework/base/_termination.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for operation termination."""
-
-import enum
-
-from grpc.framework.base import _constants
-from grpc.framework.base import _interfaces
-from grpc.framework.base import interfaces
-from grpc.framework.foundation import callable_util
-
-_CALLBACK_EXCEPTION_LOG_MESSAGE = 'Exception calling termination callback!'
-
-
-@enum.unique
-class _Requirement(enum.Enum):
-  """Symbols indicating events required for termination."""
-
-  EMISSION = 'emission'
-  TRANSMISSION = 'transmission'
-  INGESTION = 'ingestion'
-
-_FRONT_NOT_LISTENING_REQUIREMENTS = (_Requirement.TRANSMISSION,)
-_BACK_NOT_LISTENING_REQUIREMENTS = (
-    _Requirement.EMISSION, _Requirement.INGESTION,)
-_LISTENING_REQUIREMENTS = (
-    _Requirement.TRANSMISSION, _Requirement.INGESTION,)
-
-
-class _TerminationManager(_interfaces.TerminationManager):
-  """An implementation of _interfaces.TerminationManager."""
-
-  def __init__(
-      self, work_pool, utility_pool, action, requirements, local_failure):
-    """Constructor.
-
-    Args:
-      work_pool: A thread pool in which customer work will be done.
-      utility_pool: A thread pool in which work utility work will be done.
-      action: An action to call on operation termination.
-      requirements: A combination of _Requirement values identifying what
-        must finish for the operation to be considered completed.
-      local_failure: An interfaces.Outcome specifying what constitutes local
-        failure of customer work.
-    """
-    self._work_pool = work_pool
-    self._utility_pool = utility_pool
-    self._action = action
-    self._local_failure = local_failure
-    self._has_locally_failed = False
-    self._expiration_manager = None
-
-    self._outstanding_requirements = set(requirements)
-    self._outcome = None
-    self._callbacks = []
-
-  def set_expiration_manager(self, expiration_manager):
-    self._expiration_manager = expiration_manager
-
-  def _terminate(self, outcome):
-    """Terminates the operation.
-
-    Args:
-      outcome: An interfaces.Outcome describing the outcome of the operation.
-    """
-    self._expiration_manager.abort()
-    self._outstanding_requirements = None
-    callbacks = list(self._callbacks)
-    self._callbacks = None
-    self._outcome = outcome
-
-    act = callable_util.with_exceptions_logged(
-        self._action, _constants.INTERNAL_ERROR_LOG_MESSAGE)
-
-    if self._has_locally_failed:
-      self._utility_pool.submit(act, outcome)
-    else:
-      def call_callbacks_and_act(callbacks, outcome):
-        for callback in callbacks:
-          callback_outcome = callable_util.call_logging_exceptions(
-              callback, _CALLBACK_EXCEPTION_LOG_MESSAGE, outcome)
-          if callback_outcome.exception is not None:
-            outcome = self._local_failure
-            break
-        self._utility_pool.submit(act, outcome)
-
-      self._work_pool.submit(callable_util.with_exceptions_logged(
-          call_callbacks_and_act,
-          _constants.INTERNAL_ERROR_LOG_MESSAGE),
-                             callbacks, outcome)
-
-  def is_active(self):
-    """See _interfaces.TerminationManager.is_active for specification."""
-    return self._outstanding_requirements is not None
-
-  def add_callback(self, callback):
-    """See _interfaces.TerminationManager.add_callback for specification."""
-    if not self._has_locally_failed:
-      if self._outstanding_requirements is None:
-        self._work_pool.submit(
-            callable_util.with_exceptions_logged(
-                callback, _CALLBACK_EXCEPTION_LOG_MESSAGE), self._outcome)
-      else:
-        self._callbacks.append(callback)
-
-  def emission_complete(self):
-    """See superclass method for specification."""
-    if self._outstanding_requirements is not None:
-      self._outstanding_requirements.discard(_Requirement.EMISSION)
-      if not self._outstanding_requirements:
-        self._terminate(interfaces.Outcome.COMPLETED)
-
-  def transmission_complete(self):
-    """See superclass method for specification."""
-    if self._outstanding_requirements is not None:
-      self._outstanding_requirements.discard(_Requirement.TRANSMISSION)
-      if not self._outstanding_requirements:
-        self._terminate(interfaces.Outcome.COMPLETED)
-
-  def ingestion_complete(self):
-    """See superclass method for specification."""
-    if self._outstanding_requirements is not None:
-      self._outstanding_requirements.discard(_Requirement.INGESTION)
-      if not self._outstanding_requirements:
-        self._terminate(interfaces.Outcome.COMPLETED)
-
-  def abort(self, outcome):
-    """See _interfaces.TerminationManager.abort for specification."""
-    if outcome is self._local_failure:
-      self._has_failed_locally = True
-    if self._outstanding_requirements is not None:
-      self._terminate(outcome)
-
-
-def front_termination_manager(
-    work_pool, utility_pool, action, subscription_kind):
-  """Creates a TerminationManager appropriate for front-side use.
-
-  Args:
-    work_pool: A thread pool in which customer work will be done.
-    utility_pool: A thread pool in which work utility work will be done.
-    action: An action to call on operation termination.
-    subscription_kind: An interfaces.ServicedSubscription.Kind value.
-
-  Returns:
-    A TerminationManager appropriate for front-side use.
-  """
-  if subscription_kind is interfaces.ServicedSubscription.Kind.NONE:
-    requirements = _FRONT_NOT_LISTENING_REQUIREMENTS
-  else:
-    requirements = _LISTENING_REQUIREMENTS
-
-  return _TerminationManager(
-      work_pool, utility_pool, action, requirements,
-      interfaces.Outcome.SERVICED_FAILURE)
-
-
-def back_termination_manager(work_pool, utility_pool, action, subscription_kind):
-  """Creates a TerminationManager appropriate for back-side use.
-
-  Args:
-    work_pool: A thread pool in which customer work will be done.
-    utility_pool: A thread pool in which work utility work will be done.
-    action: An action to call on operation termination.
-    subscription_kind: An interfaces.ServicedSubscription.Kind value.
-
-  Returns:
-    A TerminationManager appropriate for back-side use.
-  """
-  if subscription_kind is interfaces.ServicedSubscription.Kind.NONE:
-    requirements = _BACK_NOT_LISTENING_REQUIREMENTS
-  else:
-    requirements = _LISTENING_REQUIREMENTS
-
-  return _TerminationManager(
-      work_pool, utility_pool, action, requirements,
-      interfaces.Outcome.SERVICER_FAILURE)
diff --git a/src/python/grpcio/grpc/framework/base/_transmission.py b/src/python/grpcio/grpc/framework/base/_transmission.py
deleted file mode 100644
index e2a2562..0000000
--- a/src/python/grpcio/grpc/framework/base/_transmission.py
+++ /dev/null
@@ -1,429 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for ticket transmission during an operation."""
-
-import abc
-
-import six
-
-from grpc.framework.base import _constants
-from grpc.framework.base import _interfaces
-from grpc.framework.base import interfaces
-from grpc.framework.foundation import callable_util
-
-_TRANSMISSION_EXCEPTION_LOG_MESSAGE = 'Exception during transmission!'
-
-_FRONT_TO_BACK_NO_TRANSMISSION_OUTCOMES = (
-    interfaces.Outcome.SERVICER_FAILURE,
-    )
-_BACK_TO_FRONT_NO_TRANSMISSION_OUTCOMES = (
-    interfaces.Outcome.CANCELLED,
-    interfaces.Outcome.SERVICED_FAILURE,
-    )
-
-_ABORTION_OUTCOME_TO_FRONT_TO_BACK_TICKET_KIND = {
-    interfaces.Outcome.CANCELLED:
-        interfaces.FrontToBackTicket.Kind.CANCELLATION,
-    interfaces.Outcome.EXPIRED:
-        interfaces.FrontToBackTicket.Kind.EXPIRATION,
-    interfaces.Outcome.RECEPTION_FAILURE:
-        interfaces.FrontToBackTicket.Kind.RECEPTION_FAILURE,
-    interfaces.Outcome.TRANSMISSION_FAILURE:
-        interfaces.FrontToBackTicket.Kind.TRANSMISSION_FAILURE,
-    interfaces.Outcome.SERVICED_FAILURE:
-        interfaces.FrontToBackTicket.Kind.SERVICED_FAILURE,
-    interfaces.Outcome.SERVICER_FAILURE:
-        interfaces.FrontToBackTicket.Kind.SERVICER_FAILURE,
-}
-
-_ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND = {
-    interfaces.Outcome.CANCELLED:
-        interfaces.BackToFrontTicket.Kind.CANCELLATION,
-    interfaces.Outcome.EXPIRED:
-        interfaces.BackToFrontTicket.Kind.EXPIRATION,
-    interfaces.Outcome.RECEPTION_FAILURE:
-        interfaces.BackToFrontTicket.Kind.RECEPTION_FAILURE,
-    interfaces.Outcome.TRANSMISSION_FAILURE:
-        interfaces.BackToFrontTicket.Kind.TRANSMISSION_FAILURE,
-    interfaces.Outcome.SERVICED_FAILURE:
-        interfaces.BackToFrontTicket.Kind.SERVICED_FAILURE,
-    interfaces.Outcome.SERVICER_FAILURE:
-        interfaces.BackToFrontTicket.Kind.SERVICER_FAILURE,
-}
-
-
-class _Ticketizer(six.with_metaclass(abc.ABCMeta)):
-  """Common specification of different ticket-creating behavior."""
-
-  @abc.abstractmethod
-  def ticketize(self, operation_id, sequence_number, payload, complete):
-    """Creates a ticket indicating ordinary operation progress.
-
-    Args:
-      operation_id: The operation ID for the current operation.
-      sequence_number: A sequence number for the ticket.
-      payload: A customer payload object. May be None if sequence_number is
-        zero or complete is true.
-      complete: A boolean indicating whether or not the ticket should describe
-        itself as (but for a later indication of operation abortion) the last
-        ticket to be sent.
-
-    Returns:
-      An object of an appropriate type suitable for transmission to the other
-        side of the operation.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def ticketize_abortion(self, operation_id, sequence_number, outcome):
-    """Creates a ticket indicating that the operation is aborted.
-
-    Args:
-      operation_id: The operation ID for the current operation.
-      sequence_number: A sequence number for the ticket.
-      outcome: An interfaces.Outcome value describing the operation abortion.
-
-    Returns:
-      An object of an appropriate type suitable for transmission to the other
-        side of the operation, or None if transmission is not appropriate for
-        the given outcome.
-    """
-    raise NotImplementedError()
-
-
-class _FrontTicketizer(_Ticketizer):
-  """Front-side ticket-creating behavior."""
-
-  def __init__(self, name, subscription_kind, trace_id, timeout):
-    """Constructor.
-
-    Args:
-      name: The name of the operation.
-      subscription_kind: An interfaces.ServicedSubscription.Kind value
-        describing the interest the front has in tickets sent from the back.
-      trace_id: A uuid.UUID identifying a set of related operations to which
-        this operation belongs.
-      timeout: A length of time in seconds to allow for the entire operation.
-    """
-    self._name = name
-    self._subscription_kind = subscription_kind
-    self._trace_id = trace_id
-    self._timeout = timeout
-
-  def ticketize(self, operation_id, sequence_number, payload, complete):
-    """See _Ticketizer.ticketize for specification."""
-    if sequence_number:
-      if complete:
-        kind = interfaces.FrontToBackTicket.Kind.COMPLETION
-      else:
-        kind = interfaces.FrontToBackTicket.Kind.CONTINUATION
-      return interfaces.FrontToBackTicket(
-          operation_id, sequence_number, kind, self._name,
-          self._subscription_kind, self._trace_id, payload, self._timeout)
-    else:
-      if complete:
-        kind = interfaces.FrontToBackTicket.Kind.ENTIRE
-      else:
-        kind = interfaces.FrontToBackTicket.Kind.COMMENCEMENT
-      return interfaces.FrontToBackTicket(
-          operation_id, 0, kind, self._name, self._subscription_kind,
-          self._trace_id, payload, self._timeout)
-
-  def ticketize_abortion(self, operation_id, sequence_number, outcome):
-    """See _Ticketizer.ticketize_abortion for specification."""
-    if outcome in _FRONT_TO_BACK_NO_TRANSMISSION_OUTCOMES:
-      return None
-    else:
-      kind = _ABORTION_OUTCOME_TO_FRONT_TO_BACK_TICKET_KIND[outcome]
-      return interfaces.FrontToBackTicket(
-          operation_id, sequence_number, kind, None, None, None, None, None)
-
-
-class _BackTicketizer(_Ticketizer):
-  """Back-side ticket-creating behavior."""
-
-  def ticketize(self, operation_id, sequence_number, payload, complete):
-    """See _Ticketizer.ticketize for specification."""
-    if complete:
-      kind = interfaces.BackToFrontTicket.Kind.COMPLETION
-    else:
-      kind = interfaces.BackToFrontTicket.Kind.CONTINUATION
-    return interfaces.BackToFrontTicket(
-        operation_id, sequence_number, kind, payload)
-
-  def ticketize_abortion(self, operation_id, sequence_number, outcome):
-    """See _Ticketizer.ticketize_abortion for specification."""
-    if outcome in _BACK_TO_FRONT_NO_TRANSMISSION_OUTCOMES:
-      return None
-    else:
-      kind = _ABORTION_OUTCOME_TO_BACK_TO_FRONT_TICKET_KIND[outcome]
-      return interfaces.BackToFrontTicket(
-          operation_id, sequence_number, kind, None)
-
-
-class TransmissionManager(six.with_metaclass(abc.ABCMeta, _interfaces.TransmissionManager)):
-  """A _interfaces.TransmissionManager on which other managers may be set."""
-
-  @abc.abstractmethod
-  def set_ingestion_and_expiration_managers(
-      self, ingestion_manager, expiration_manager):
-    """Sets two of the other managers with which this manager may interact.
-
-    Args:
-      ingestion_manager: The _interfaces.IngestionManager associated with the
-        current operation.
-      expiration_manager: The _interfaces.ExpirationManager associated with the
-        current operation.
-    """
-    raise NotImplementedError()
-
-
-class _EmptyTransmissionManager(TransmissionManager):
-  """A completely no-operative _interfaces.TransmissionManager."""
-
-  def set_ingestion_and_expiration_managers(
-      self, ingestion_manager, expiration_manager):
-    """See overriden method for specification."""
-
-  def inmit(self, emission, complete):
-    """See _interfaces.TransmissionManager.inmit for specification."""
-
-  def abort(self, outcome):
-    """See _interfaces.TransmissionManager.abort for specification."""
-
-
-class _TransmittingTransmissionManager(TransmissionManager):
-  """A TransmissionManager implementation that sends tickets."""
-
-  def __init__(
-      self, lock, pool, callback, operation_id, ticketizer,
-      termination_manager):
-    """Constructor.
-
-    Args:
-      lock: The operation-servicing-wide lock object.
-      pool: A thread pool in which the work of transmitting tickets will be
-        performed.
-      callback: A callable that accepts tickets and sends them to the other side
-        of the operation.
-      operation_id: The operation's ID.
-      ticketizer: A _Ticketizer for ticket creation.
-      termination_manager: The _interfaces.TerminationManager associated with
-        this operation.
-    """
-    self._lock = lock
-    self._pool = pool
-    self._callback = callback
-    self._operation_id = operation_id
-    self._ticketizer = ticketizer
-    self._termination_manager = termination_manager
-    self._ingestion_manager = None
-    self._expiration_manager = None
-
-    self._emissions = []
-    self._emission_complete = False
-    self._outcome = None
-    self._lowest_unused_sequence_number = 0
-    self._transmitting = False
-
-  def set_ingestion_and_expiration_managers(
-      self, ingestion_manager, expiration_manager):
-    """See overridden method for specification."""
-    self._ingestion_manager = ingestion_manager
-    self._expiration_manager = expiration_manager
-
-  def _lead_ticket(self, emission, complete):
-    """Creates a ticket suitable for leading off the transmission loop.
-
-    Args:
-      emission: A customer payload object to be sent to the other side of the
-        operation.
-      complete: Whether or not the sequence of customer payloads ends with
-        the passed object.
-
-    Returns:
-      A ticket with which to lead off the transmission loop.
-    """
-    sequence_number = self._lowest_unused_sequence_number
-    self._lowest_unused_sequence_number += 1
-    return self._ticketizer.ticketize(
-        self._operation_id, sequence_number, emission, complete)
-
-  def _abortive_response_ticket(self, outcome):
-    """Creates a ticket indicating operation abortion.
-
-    Args:
-      outcome: An interfaces.Outcome value describing operation abortion.
-
-    Returns:
-      A ticket indicating operation abortion.
-    """
-    ticket = self._ticketizer.ticketize_abortion(
-        self._operation_id, self._lowest_unused_sequence_number, outcome)
-    if ticket is None:
-      return None
-    else:
-      self._lowest_unused_sequence_number += 1
-      return ticket
-
-  def _next_ticket(self):
-    """Creates the next ticket to be sent to the other side of the operation.
-
-    Returns:
-      A (completed, ticket) tuple comprised of a boolean indicating whether or
-        not the sequence of tickets has completed normally and a ticket to send
-        to the other side if the sequence of tickets hasn't completed. The tuple
-        will never have both a True first element and a non-None second element.
-    """
-    if self._emissions is None:
-      return False, None
-    elif self._outcome is None:
-      if self._emissions:
-        payload = self._emissions.pop(0)
-        complete = self._emission_complete and not self._emissions
-        sequence_number = self._lowest_unused_sequence_number
-        self._lowest_unused_sequence_number += 1
-        return complete, self._ticketizer.ticketize(
-            self._operation_id, sequence_number, payload, complete)
-      else:
-        return self._emission_complete, None
-    else:
-      ticket = self._abortive_response_ticket(self._outcome)
-      self._emissions = None
-      return False, None if ticket is None else ticket
-
-  def _transmit(self, ticket):
-    """Commences the transmission loop sending tickets.
-
-    Args:
-      ticket: A ticket to be sent to the other side of the operation.
-    """
-    def transmit(ticket):
-      while True:
-        transmission_outcome = callable_util.call_logging_exceptions(
-            self._callback, _TRANSMISSION_EXCEPTION_LOG_MESSAGE, ticket)
-        if transmission_outcome.exception is None:
-          with self._lock:
-            complete, ticket = self._next_ticket()
-            if ticket is None:
-              if complete:
-                self._termination_manager.transmission_complete()
-              self._transmitting = False
-              return
-        else:
-          with self._lock:
-            self._emissions = None
-            self._termination_manager.abort(
-                interfaces.Outcome.TRANSMISSION_FAILURE)
-            self._ingestion_manager.abort()
-            self._expiration_manager.abort()
-            self._transmitting = False
-            return
-
-    self._pool.submit(callable_util.with_exceptions_logged(
-        transmit, _constants.INTERNAL_ERROR_LOG_MESSAGE), ticket)
-    self._transmitting = True
-
-  def inmit(self, emission, complete):
-    """See _interfaces.TransmissionManager.inmit for specification."""
-    if self._emissions is not None and self._outcome is None:
-      self._emission_complete = complete
-      if self._transmitting:
-        self._emissions.append(emission)
-      else:
-        self._transmit(self._lead_ticket(emission, complete))
-
-  def abort(self, outcome):
-    """See _interfaces.TransmissionManager.abort for specification."""
-    if self._emissions is not None and self._outcome is None:
-      self._outcome = outcome
-      if not self._transmitting:
-        ticket = self._abortive_response_ticket(outcome)
-        self._emissions = None
-        if ticket is not None:
-          self._transmit(ticket)
-
-
-def front_transmission_manager(
-    lock, pool, callback, operation_id, name, subscription_kind, trace_id,
-    timeout, termination_manager):
-  """Creates a TransmissionManager appropriate for front-side use.
-
-  Args:
-    lock: The operation-servicing-wide lock object.
-    pool: A thread pool in which the work of transmitting tickets will be
-      performed.
-    callback: A callable that accepts tickets and sends them to the other side
-      of the operation.
-    operation_id: The operation's ID.
-    name: The name of the operation.
-    subscription_kind: An interfaces.ServicedSubscription.Kind value
-      describing the interest the front has in tickets sent from the back.
-    trace_id: A uuid.UUID identifying a set of related operations to which
-      this operation belongs.
-    timeout: A length of time in seconds to allow for the entire operation.
-    termination_manager: The _interfaces.TerminationManager associated with
-      this operation.
-
-  Returns:
-    A TransmissionManager appropriate for front-side use.
-  """
-  return _TransmittingTransmissionManager(
-      lock, pool, callback, operation_id, _FrontTicketizer(
-          name, subscription_kind, trace_id, timeout),
-      termination_manager)
-
-
-def back_transmission_manager(
-    lock, pool, callback, operation_id, termination_manager,
-    subscription_kind):
-  """Creates a TransmissionManager appropriate for back-side use.
-
-  Args:
-    lock: The operation-servicing-wide lock object.
-    pool: A thread pool in which the work of transmitting tickets will be
-      performed.
-    callback: A callable that accepts tickets and sends them to the other side
-      of the operation.
-    operation_id: The operation's ID.
-    termination_manager: The _interfaces.TerminationManager associated with
-      this operation.
-    subscription_kind: An interfaces.ServicedSubscription.Kind value
-      describing the interest the front has in tickets sent from the back.
-
-  Returns:
-    A TransmissionManager appropriate for back-side use.
-  """
-  if subscription_kind is interfaces.ServicedSubscription.Kind.NONE:
-    return _EmptyTransmissionManager()
-  else:
-    return _TransmittingTransmissionManager(
-        lock, pool, callback, operation_id, _BackTicketizer(),
-        termination_manager)
diff --git a/src/python/grpcio/grpc/framework/base/exceptions.py b/src/python/grpcio/grpc/framework/base/exceptions.py
deleted file mode 100644
index b8f4752..0000000
--- a/src/python/grpcio/grpc/framework/base/exceptions.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Exceptions defined and used by the base layer of RPC Framework."""
-
-
-class NoSuchMethodError(Exception):
-  """Indicates that an operation with an unrecognized name has been called."""
diff --git a/src/python/grpcio/grpc/framework/base/implementations.py b/src/python/grpcio/grpc/framework/base/implementations.py
deleted file mode 100644
index 5656f9f..0000000
--- a/src/python/grpcio/grpc/framework/base/implementations.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Entry points into the ticket-exchange-based base layer implementation."""
-
-# interfaces is referenced from specification in this module.
-from grpc.framework.base import _ends
-from grpc.framework.base import interfaces  # pylint: disable=unused-import
-
-
-def front_link(work_pool, transmission_pool, utility_pool):
-  """Factory function for creating interfaces.FrontLinks.
-
-  Args:
-    work_pool: A thread pool to be used for doing work within the created
-      FrontLink object.
-    transmission_pool: A thread pool to be used within the created FrontLink
-      object for transmitting values to a joined RearLink object.
-    utility_pool: A thread pool to be used within the created FrontLink object
-      for utility tasks.
-
-  Returns:
-    An interfaces.FrontLink.
-  """
-  return _ends.FrontLink(work_pool, transmission_pool, utility_pool)
-
-
-def back_link(
-    servicer, work_pool, transmission_pool, utility_pool, default_timeout,
-    maximum_timeout):
-  """Factory function for creating interfaces.BackLinks.
-
-  Args:
-    servicer: An interfaces.Servicer for servicing operations.
-    work_pool: A thread pool to be used for doing work within the created
-      BackLink object.
-    transmission_pool: A thread pool to be used within the created BackLink
-      object for transmitting values to a joined ForeLink object.
-    utility_pool: A thread pool to be used within the created BackLink object
-      for utility tasks.
-    default_timeout: A length of time in seconds to be used as the default
-      time alloted for a single operation.
-    maximum_timeout: A length of time in seconds to be used as the maximum
-      time alloted for a single operation.
-
-  Returns:
-    An interfaces.BackLink.
-  """
-  return _ends.BackLink(
-      servicer, work_pool, transmission_pool, utility_pool, default_timeout,
-      maximum_timeout)
diff --git a/src/python/grpcio/grpc/framework/base/in_memory.py b/src/python/grpcio/grpc/framework/base/in_memory.py
deleted file mode 100644
index c92d0bc..0000000
--- a/src/python/grpcio/grpc/framework/base/in_memory.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""In-memory implementations of base layer interfaces."""
-
-import threading
-
-from grpc.framework.base import _constants
-from grpc.framework.base import interfaces
-from grpc.framework.foundation import callable_util
-
-
-class _Serializer(object):
-  """A utility for serializing values that may arrive concurrently."""
-
-  def __init__(self, pool):
-    self._lock = threading.Lock()
-    self._pool = pool
-    self._sink = None
-    self._spinning = False
-    self._values = []
-
-  def _spin(self, sink, value):
-    while True:
-      sink(value)
-      with self._lock:
-        if self._sink is None or not self._values:
-          self._spinning = False
-          return
-        else:
-          sink, value = self._sink, self._values.pop(0)
-
-  def set_sink(self, sink):
-    with self._lock:
-      self._sink = sink
-      if sink is not None and self._values and not self._spinning:
-        self._spinning = True
-        self._pool.submit(
-            callable_util.with_exceptions_logged(
-                self._spin, _constants.INTERNAL_ERROR_LOG_MESSAGE),
-            sink, self._values.pop(0))
-
-  def add_value(self, value):
-    with self._lock:
-      if self._sink and not self._spinning:
-        self._spinning = True
-        self._pool.submit(
-            callable_util.with_exceptions_logged(
-                self._spin, _constants.INTERNAL_ERROR_LOG_MESSAGE),
-            self._sink, value)
-      else:
-        self._values.append(value)
-
-
-class Link(interfaces.ForeLink, interfaces.RearLink):
-  """A trivial implementation of interfaces.ForeLink and interfaces.RearLink."""
-
-  def __init__(self, pool):
-    """Constructor.
-
-    Args:
-      pool: A thread pool to be used for serializing ticket exchange in each
-        direction.
-    """
-    self._front_to_back = _Serializer(pool)
-    self._back_to_front = _Serializer(pool)
-
-  def join_fore_link(self, fore_link):
-    """See interfaces.RearLink.join_fore_link for specification."""
-    self._back_to_front.set_sink(fore_link.accept_back_to_front_ticket)
-
-  def join_rear_link(self, rear_link):
-    """See interfaces.ForeLink.join_rear_link for specification."""
-    self._front_to_back.set_sink(rear_link.accept_front_to_back_ticket)
-
-  def accept_front_to_back_ticket(self, ticket):
-    """See interfaces.ForeLink.accept_front_to_back_ticket for specification."""
-    self._front_to_back.add_value(ticket)
-
-  def accept_back_to_front_ticket(self, ticket):
-    """See interfaces.RearLink.accept_back_to_front_ticket for specification."""
-    self._back_to_front.add_value(ticket)
diff --git a/src/python/grpcio/grpc/framework/base/interfaces.py b/src/python/grpcio/grpc/framework/base/interfaces.py
deleted file mode 100644
index 995b51c..0000000
--- a/src/python/grpcio/grpc/framework/base/interfaces.py
+++ /dev/null
@@ -1,353 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Interfaces defined and used by the base layer of RPC Framework."""
-
-import abc
-import collections
-import enum
-
-import six
-
-# stream is referenced from specification in this module.
-from grpc.framework.foundation import stream  # pylint: disable=unused-import
-
-
-@enum.unique
-class Outcome(enum.Enum):
-  """Operation outcomes."""
-
-  COMPLETED = 'completed'
-  CANCELLED = 'cancelled'
-  EXPIRED = 'expired'
-  RECEPTION_FAILURE = 'reception failure'
-  TRANSMISSION_FAILURE = 'transmission failure'
-  SERVICER_FAILURE = 'servicer failure'
-  SERVICED_FAILURE = 'serviced failure'
-
-
-class OperationContext(six.with_metaclass(abc.ABCMeta)):
-  """Provides operation-related information and action.
-
-  Attributes:
-    trace_id: A uuid.UUID identifying a particular set of related operations.
-  """
-
-  @abc.abstractmethod
-  def is_active(self):
-    """Describes whether the operation is active or has terminated."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def add_termination_callback(self, callback):
-    """Adds a function to be called upon operation termination.
-
-    Args:
-      callback: A callable that will be passed an Outcome value.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def time_remaining(self):
-    """Describes the length of allowed time remaining for the operation.
-
-    Returns:
-      A nonnegative float indicating the length of allowed time in seconds
-      remaining for the operation to complete before it is considered to have
-      timed out.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def fail(self, exception):
-    """Indicates that the operation has failed.
-
-    Args:
-      exception: An exception germane to the operation failure. May be None.
-    """
-    raise NotImplementedError()
-
-
-class Servicer(six.with_metaclass(abc.ABCMeta)):
-  """Interface for service implementations."""
-
-  @abc.abstractmethod
-  def service(self, name, context, output_consumer):
-    """Services an operation.
-
-    Args:
-      name: The name of the operation.
-      context: A ServicerContext object affording contextual information and
-        actions.
-      output_consumer: A stream.Consumer that will accept output values of
-        the operation.
-
-    Returns:
-      A stream.Consumer that will accept input values for the operation.
-
-    Raises:
-      exceptions.NoSuchMethodError: If this Servicer affords no method with the
-        given name.
-      abandonment.Abandoned: If the operation has been aborted and there no
-        longer is any reason to service the operation.
-    """
-    raise NotImplementedError()
-
-
-class Operation(six.with_metaclass(abc.ABCMeta)):
-  """Representation of an in-progress operation.
-
-  Attributes:
-    consumer: A stream.Consumer into which payloads constituting the operation's
-      input may be passed.
-    context: An OperationContext affording information and action about the
-      operation.
-  """
-
-  @abc.abstractmethod
-  def cancel(self):
-    """Cancels this operation."""
-    raise NotImplementedError()
-
-
-class ServicedIngestor(six.with_metaclass(abc.ABCMeta)):
-  """Responsible for accepting the result of an operation."""
-
-  @abc.abstractmethod
-  def consumer(self, operation_context):
-    """Affords a consumer to which operation results will be passed.
-
-    Args:
-      operation_context: An OperationContext object for the current operation.
-
-    Returns:
-      A stream.Consumer to which the results of the current operation will be
-        passed.
-
-    Raises:
-      abandonment.Abandoned: If the operation has been aborted and there no
-        longer is any reason to service the operation.
-    """
-    raise NotImplementedError()
-
-
-class ServicedSubscription(six.with_metaclass(abc.ABCMeta)):
-  """A sum type representing a serviced's interest in an operation.
-
-  Attributes:
-    kind: A Kind value.
-    ingestor: A ServicedIngestor. Must be present if kind is Kind.FULL. Must
-      be None if kind is Kind.TERMINATION_ONLY or Kind.NONE.
-  """
-
-  @enum.unique
-  class Kind(enum.Enum):
-    """Kinds of subscription."""
-
-    FULL = 'full'
-    TERMINATION_ONLY = 'termination only'
-    NONE = 'none'
-
-
-class End(six.with_metaclass(abc.ABCMeta)):
-  """Common type for entry-point objects on both sides of an operation."""
-
-  @abc.abstractmethod
-  def operation_stats(self):
-    """Reports the number of terminated operations broken down by outcome.
-
-    Returns:
-      A dictionary from Outcome value to an integer identifying the number
-        of operations that terminated with that outcome.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def add_idle_action(self, action):
-    """Adds an action to be called when this End has no ongoing operations.
-
-    Args:
-      action: A callable that accepts no arguments.
-    """
-    raise NotImplementedError()
-
-
-class Front(six.with_metaclass(abc.ABCMeta, End)):
-  """Clientish objects that afford the invocation of operations."""
-
-  @abc.abstractmethod
-  def operate(
-      self, name, payload, complete, timeout, subscription, trace_id):
-    """Commences an operation.
-
-    Args:
-      name: The name of the method invoked for the operation.
-      payload: An initial payload for the operation. May be None.
-      complete: A boolean indicating whether or not additional payloads to be
-        sent to the servicer may be supplied after this call.
-      timeout: A length of time in seconds to allow for the operation.
-      subscription: A ServicedSubscription for the operation.
-      trace_id: A uuid.UUID identifying a set of related operations to which
-        this operation belongs.
-
-    Returns:
-      An Operation object affording information and action about the operation
-        in progress.
-    """
-    raise NotImplementedError()
-
-
-class Back(six.with_metaclass(abc.ABCMeta, End)):
-  """Serverish objects that perform the work of operations."""
-
-
-class FrontToBackTicket(
-    collections.namedtuple(
-        'FrontToBackTicket',
-        ['operation_id', 'sequence_number', 'kind', 'name', 'subscription',
-         'trace_id', 'payload', 'timeout'])):
-  """A sum type for all values sent from a front to a back.
-
-  Attributes:
-    operation_id: A unique-with-respect-to-equality hashable object identifying
-      a particular operation.
-    sequence_number: A zero-indexed integer sequence number identifying the
-      ticket's place among all the tickets sent from front to back for this
-      particular operation. Must be zero if kind is Kind.COMMENCEMENT or
-      Kind.ENTIRE. Must be positive for any other kind.
-    kind: A Kind value describing the overall kind of ticket.
-    name: The name of an operation. Must be present if kind is Kind.COMMENCEMENT
-      or Kind.ENTIRE. Must be None for any other kind.
-    subscription: An ServicedSubscription.Kind value describing the interest
-      the front has in tickets sent from the back. Must be present if
-      kind is Kind.COMMENCEMENT or Kind.ENTIRE. Must be None for any other kind.
-    trace_id: A uuid.UUID identifying a set of related operations to which this
-      operation belongs. May be None.
-    payload: A customer payload object. Must be present if kind is
-      Kind.CONTINUATION. Must be None if kind is Kind.CANCELLATION. May be None
-      for any other kind.
-    timeout: An optional length of time (measured from the beginning of the
-      operation) to allow for the entire operation. If None, a default value on
-      the back will be used. If present and excessively large, the back may
-      limit the operation to a smaller duration of its choice. May be present
-      for any ticket kind; setting a value on a later ticket allows fronts
-      to request time extensions (or even time reductions!) on in-progress
-      operations.
-  """
-
-  @enum.unique
-  class Kind(enum.Enum):
-    """Identifies the overall kind of a FrontToBackTicket."""
-
-    COMMENCEMENT = 'commencement'
-    CONTINUATION = 'continuation'
-    COMPLETION = 'completion'
-    ENTIRE = 'entire'
-    CANCELLATION = 'cancellation'
-    EXPIRATION = 'expiration'
-    SERVICER_FAILURE = 'servicer failure'
-    SERVICED_FAILURE = 'serviced failure'
-    RECEPTION_FAILURE = 'reception failure'
-    TRANSMISSION_FAILURE = 'transmission failure'
-
-
-class BackToFrontTicket(
-    collections.namedtuple(
-        'BackToFrontTicket',
-        ['operation_id', 'sequence_number', 'kind', 'payload'])):
-  """A sum type for all values sent from a back to a front.
-
-  Attributes:
-    operation_id: A unique-with-respect-to-equality hashable object identifying
-      a particular operation.
-    sequence_number: A zero-indexed integer sequence number identifying the
-      ticket's place among all the tickets sent from back to front for this
-      particular operation.
-    kind: A Kind value describing the overall kind of ticket.
-    payload: A customer payload object. Must be present if kind is
-      Kind.CONTINUATION. May be None if kind is Kind.COMPLETION. Must be None
-      otherwise.
-  """
-
-  @enum.unique
-  class Kind(enum.Enum):
-    """Identifies the overall kind of a BackToFrontTicket."""
-
-    CONTINUATION = 'continuation'
-    COMPLETION = 'completion'
-    CANCELLATION = 'cancellation'
-    EXPIRATION = 'expiration'
-    SERVICER_FAILURE = 'servicer failure'
-    SERVICED_FAILURE = 'serviced failure'
-    RECEPTION_FAILURE = 'reception failure'
-    TRANSMISSION_FAILURE = 'transmission failure'
-
-
-class ForeLink(six.with_metaclass(abc.ABCMeta)):
-  """Accepts back-to-front tickets and emits front-to-back tickets."""
-
-  @abc.abstractmethod
-  def accept_back_to_front_ticket(self, ticket):
-    """Accept a BackToFrontTicket.
-
-    Args:
-      ticket: Any BackToFrontTicket.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def join_rear_link(self, rear_link):
-    """Mates this object with a peer with which it will exchange tickets."""
-    raise NotImplementedError()
-
-
-class RearLink(six.with_metaclass(abc.ABCMeta)):
-  """Accepts front-to-back tickets and emits back-to-front tickets."""
-
-  @abc.abstractmethod
-  def accept_front_to_back_ticket(self, ticket):
-    """Accepts a FrontToBackTicket.
-
-    Args:
-      ticket: Any FrontToBackTicket.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def join_fore_link(self, fore_link):
-    """Mates this object with a peer with which it will exchange tickets."""
-    raise NotImplementedError()
-
-
-class FrontLink(six.with_metaclass(abc.ABCMeta, Front, ForeLink)):
-  """Clientish objects that operate by sending and receiving tickets."""
-
-
-class BackLink(six.with_metaclass(abc.ABCMeta, Back, RearLink)):
-  """Serverish objects that operate by sending and receiving tickets."""
diff --git a/src/python/grpcio/grpc/framework/base/null.py b/src/python/grpcio/grpc/framework/base/null.py
deleted file mode 100644
index 1e30d45..0000000
--- a/src/python/grpcio/grpc/framework/base/null.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Null links that ignore tickets passed to them."""
-
-from grpc.framework.base import interfaces
-
-
-class _NullForeLink(interfaces.ForeLink):
-  """A do-nothing ForeLink."""
-
-  def accept_back_to_front_ticket(self, ticket):
-    pass
-
-  def join_rear_link(self, rear_link):
-    raise NotImplementedError()
-
-
-class _NullRearLink(interfaces.RearLink):
-  """A do-nothing RearLink."""
-
-  def accept_front_to_back_ticket(self, ticket):
-    pass
-
-  def join_fore_link(self, fore_link):
-    raise NotImplementedError()
-
-
-NULL_FORE_LINK = _NullForeLink()
-NULL_REAR_LINK = _NullRearLink()
diff --git a/src/python/grpcio/grpc/framework/base/util.py b/src/python/grpcio/grpc/framework/base/util.py
deleted file mode 100644
index c832c82..0000000
--- a/src/python/grpcio/grpc/framework/base/util.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Utilities helpful for working with the base layer of RPC Framework."""
-
-import collections
-import threading
-
-from grpc.framework.base import interfaces
-
-
-class _ServicedSubscription(
-    collections.namedtuple('_ServicedSubscription', ['kind', 'ingestor']),
-    interfaces.ServicedSubscription):
-  """See interfaces.ServicedSubscription for specification."""
-
-_NONE_SUBSCRIPTION = _ServicedSubscription(
-    interfaces.ServicedSubscription.Kind.NONE, None)
-_TERMINATION_ONLY_SUBSCRIPTION = _ServicedSubscription(
-    interfaces.ServicedSubscription.Kind.TERMINATION_ONLY, None)
-
-
-def none_serviced_subscription():
-  """Creates a "none" interfaces.ServicedSubscription object.
-
-  Returns:
-    An interfaces.ServicedSubscription indicating no subscription to an
-      operation's results (such as would be the case for a fire-and-forget
-      operation invocation).
-  """
-  return _NONE_SUBSCRIPTION
-
-
-def termination_only_serviced_subscription():
-  """Creates a "termination only" interfaces.ServicedSubscription object.
-
-  Returns:
-    An interfaces.ServicedSubscription indicating that the front-side customer
-      is interested only in the overall termination outcome of the operation
-      (such as completion or expiration) and would ignore the actual results of
-      the operation.
-  """
-  return _TERMINATION_ONLY_SUBSCRIPTION
-
-
-def full_serviced_subscription(ingestor):
-  """Creates a "full" interfaces.ServicedSubscription object.
-
-  Args:
-    ingestor: An interfaces.ServicedIngestor.
-
-  Returns:
-    An interfaces.ServicedSubscription object indicating a full
-      subscription.
-  """
-  return _ServicedSubscription(
-      interfaces.ServicedSubscription.Kind.FULL, ingestor)
-
-
-def wait_for_idle(end):
-  """Waits for an interfaces.End to complete all operations.
-
-  Args:
-    end: Any interfaces.End.
-  """
-  event = threading.Event()
-  end.add_idle_action(event.set)
-  event.wait()
diff --git a/src/python/grpcio/grpc/framework/face/__init__.py b/src/python/grpcio/grpc/framework/face/__init__.py
deleted file mode 100644
index bff74be..0000000
--- a/src/python/grpcio/grpc/framework/face/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-import warnings
-
-warnings.simplefilter('always', DeprecationWarning)
-warnings.warn('the alpha API (includes this package) is deprecated, '
-              'unmaintained, and no longer tested. Please migrate to the beta '
-              'API.', DeprecationWarning, stacklevel=2)
diff --git a/src/python/grpcio/grpc/framework/face/_calls.py b/src/python/grpcio/grpc/framework/face/_calls.py
deleted file mode 100644
index 87edeb0..0000000
--- a/src/python/grpcio/grpc/framework/face/_calls.py
+++ /dev/null
@@ -1,422 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Utility functions for invoking RPCs."""
-
-import sys
-import threading
-
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.base import util as base_util
-from grpc.framework.face import _control
-from grpc.framework.face import interfaces
-from grpc.framework.foundation import callable_util
-from grpc.framework.foundation import future
-
-_ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!'
-_DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!'
-
-
-class _RendezvousServicedIngestor(base_interfaces.ServicedIngestor):
-
-  def __init__(self, rendezvous):
-    self._rendezvous = rendezvous
-
-  def consumer(self, operation_context):
-    return self._rendezvous
-
-
-class _EventServicedIngestor(base_interfaces.ServicedIngestor):
-
-  def __init__(self, result_consumer, abortion_callback):
-    self._result_consumer = result_consumer
-    self._abortion_callback = abortion_callback
-
-  def consumer(self, operation_context):
-    operation_context.add_termination_callback(
-        _control.as_operation_termination_callback(self._abortion_callback))
-    return self._result_consumer
-
-
-def _rendezvous_subscription(rendezvous):
-  return base_util.full_serviced_subscription(
-      _RendezvousServicedIngestor(rendezvous))
-
-
-def _unary_event_subscription(completion_callback, abortion_callback):
-  return base_util.full_serviced_subscription(
-      _EventServicedIngestor(
-          _control.UnaryConsumer(completion_callback), abortion_callback))
-
-
-def _stream_event_subscription(result_consumer, abortion_callback):
-  return base_util.full_serviced_subscription(
-      _EventServicedIngestor(result_consumer, abortion_callback))
-
-
-# NOTE(nathaniel): This class has some extremely special semantics around
-# cancellation that allow it to be used by both "blocking" APIs and "futures"
-# APIs.
-#
-# Since futures.Future defines its own exception for cancellation, we want these
-# objects, when returned by methods of a returning-Futures-from-other-methods
-# object, to raise the same exception for cancellation. But that's weird in a
-# blocking API - why should this object, also returned by methods of blocking
-# APIs, raise exceptions from the "future" module? Should we do something like
-# have this class be parameterized by the type of exception that it raises in
-# cancellation circumstances?
-#
-# We don't have to take such a dramatic step: since blocking APIs define no
-# cancellation semantics whatsoever, there is no supported way for
-# blocking-API-users of these objects to cancel RPCs, and thus no supported way
-# for them to see an exception the type of which would be weird to them.
-#
-# Bonus: in both blocking and futures APIs, this object still properly raises
-# exceptions.CancellationError for any *server-side cancellation* of an RPC.
-class _OperationCancellableIterator(interfaces.CancellableIterator):
-  """An interfaces.CancellableIterator for response-streaming operations."""
-
-  def __init__(self, rendezvous, operation):
-    self._lock = threading.Lock()
-    self._rendezvous = rendezvous
-    self._operation = operation
-    self._cancelled = False
-
-  def __iter__(self):
-    return self
-
-  def next(self):
-    with self._lock:
-      if self._cancelled:
-        raise future.CancelledError()
-    return next(self._rendezvous)
-
-  def cancel(self):
-    with self._lock:
-      self._cancelled = True
-    self._operation.cancel()
-    self._rendezvous.set_outcome(base_interfaces.Outcome.CANCELLED)
-
-
-class _OperationFuture(future.Future):
-  """A future.Future interface to an operation."""
-
-  def __init__(self, rendezvous, operation):
-    self._condition = threading.Condition()
-    self._rendezvous = rendezvous
-    self._operation = operation
-
-    self._cancelled = False
-    self._computed = False
-    self._payload = None
-    self._exception = None
-    self._traceback = None
-    self._callbacks = []
-
-  def cancel(self):
-    """See future.Future.cancel for specification."""
-    with self._condition:
-      if not self._cancelled and not self._computed:
-        self._operation.cancel()
-        self._cancelled = True
-        self._condition.notify_all()
-    return False
-
-  def cancelled(self):
-    """See future.Future.cancelled for specification."""
-    with self._condition:
-      return self._cancelled
-
-  def running(self):
-    """See future.Future.running for specification."""
-    with self._condition:
-      return not self._cancelled and not self._computed
-
-  def done(self):
-    """See future.Future.done for specification."""
-    with self._condition:
-      return self._cancelled or self._computed
-
-  def result(self, timeout=None):
-    """See future.Future.result for specification."""
-    with self._condition:
-      if self._cancelled:
-        raise future.CancelledError()
-      if self._computed:
-        if self._payload is None:
-          raise self._exception  # pylint: disable=raising-bad-type
-        else:
-          return self._payload
-
-      condition = threading.Condition()
-      def notify_condition(unused_future):
-        with condition:
-          condition.notify()
-      self._callbacks.append(notify_condition)
-
-    with condition:
-      condition.wait(timeout=timeout)
-
-    with self._condition:
-      if self._cancelled:
-        raise future.CancelledError()
-      elif self._computed:
-        if self._payload is None:
-          raise self._exception  # pylint: disable=raising-bad-type
-        else:
-          return self._payload
-      else:
-        raise future.TimeoutError()
-
-  def exception(self, timeout=None):
-    """See future.Future.exception for specification."""
-    with self._condition:
-      if self._cancelled:
-        raise future.CancelledError()
-      if self._computed:
-        return self._exception
-
-      condition = threading.Condition()
-      def notify_condition(unused_future):
-        with condition:
-          condition.notify()
-      self._callbacks.append(notify_condition)
-
-    with condition:
-      condition.wait(timeout=timeout)
-
-    with self._condition:
-      if self._cancelled:
-        raise future.CancelledError()
-      elif self._computed:
-        return self._exception
-      else:
-        raise future.TimeoutError()
-
-  def traceback(self, timeout=None):
-    """See future.Future.traceback for specification."""
-    with self._condition:
-      if self._cancelled:
-        raise future.CancelledError()
-      if self._computed:
-        return self._traceback
-
-      condition = threading.Condition()
-      def notify_condition(unused_future):
-        with condition:
-          condition.notify()
-      self._callbacks.append(notify_condition)
-
-    with condition:
-      condition.wait(timeout=timeout)
-
-    with self._condition:
-      if self._cancelled:
-        raise future.CancelledError()
-      elif self._computed:
-        return self._traceback
-      else:
-        raise future.TimeoutError()
-
-  def add_done_callback(self, fn):
-    """See future.Future.add_done_callback for specification."""
-    with self._condition:
-      if self._callbacks is not None:
-        self._callbacks.append(fn)
-        return
-
-    callable_util.call_logging_exceptions(fn, _DONE_CALLBACK_LOG_MESSAGE, self)
-
-  def on_operation_termination(self, operation_outcome):
-    """Indicates to this object that the operation has terminated.
-
-    Args:
-      operation_outcome: A base_interfaces.Outcome value indicating the
-        outcome of the operation.
-    """
-    with self._condition:
-      cancelled = self._cancelled
-      if cancelled:
-        callbacks = list(self._callbacks)
-        self._callbacks = None
-      else:
-        rendezvous = self._rendezvous
-
-    if not cancelled:
-      payload = None
-      exception = None
-      traceback = None
-      if operation_outcome == base_interfaces.Outcome.COMPLETED:
-        try:
-          payload = next(rendezvous)
-        except Exception as e:  # pylint: disable=broad-except
-          exception = e
-          traceback = sys.exc_info()[2]
-      else:
-        try:
-          # We raise and then immediately catch in order to create a traceback.
-          raise _control.abortion_outcome_to_exception(operation_outcome)
-        except Exception as e:  # pylint: disable=broad-except
-          exception = e
-          traceback = sys.exc_info()[2]
-      with self._condition:
-        if not self._cancelled:
-          self._computed = True
-          self._payload = payload
-          self._exception = exception
-          self._traceback = traceback
-        callbacks = list(self._callbacks)
-        self._callbacks = None
-
-    for callback in callbacks:
-      callable_util.call_logging_exceptions(
-          callback, _DONE_CALLBACK_LOG_MESSAGE, self)
-
-
-class _Call(interfaces.Call):
-
-  def __init__(self, operation):
-    self._operation = operation
-    self.context = _control.RpcContext(operation.context)
-
-  def cancel(self):
-    self._operation.cancel()
-
-
-def blocking_value_in_value_out(front, name, payload, timeout, trace_id):
-  """Services in a blocking fashion a value-in value-out servicer method."""
-  rendezvous = _control.Rendezvous()
-  subscription = _rendezvous_subscription(rendezvous)
-  operation = front.operate(
-      name, payload, True, timeout, subscription, trace_id)
-  operation.context.add_termination_callback(rendezvous.set_outcome)
-  return next(rendezvous)
-
-
-def future_value_in_value_out(front, name, payload, timeout, trace_id):
-  """Services a value-in value-out servicer method by returning a Future."""
-  rendezvous = _control.Rendezvous()
-  subscription = _rendezvous_subscription(rendezvous)
-  operation = front.operate(
-      name, payload, True, timeout, subscription, trace_id)
-  operation.context.add_termination_callback(rendezvous.set_outcome)
-  operation_future = _OperationFuture(rendezvous, operation)
-  operation.context.add_termination_callback(
-      operation_future.on_operation_termination)
-  return operation_future
-
-
-def inline_value_in_stream_out(front, name, payload, timeout, trace_id):
-  """Services a value-in stream-out servicer method."""
-  rendezvous = _control.Rendezvous()
-  subscription = _rendezvous_subscription(rendezvous)
-  operation = front.operate(
-      name, payload, True, timeout, subscription, trace_id)
-  operation.context.add_termination_callback(rendezvous.set_outcome)
-  return _OperationCancellableIterator(rendezvous, operation)
-
-
-def blocking_stream_in_value_out(
-    front, name, payload_iterator, timeout, trace_id):
-  """Services in a blocking fashion a stream-in value-out servicer method."""
-  rendezvous = _control.Rendezvous()
-  subscription = _rendezvous_subscription(rendezvous)
-  operation = front.operate(name, None, False, timeout, subscription, trace_id)
-  operation.context.add_termination_callback(rendezvous.set_outcome)
-  for payload in payload_iterator:
-    operation.consumer.consume(payload)
-  operation.consumer.terminate()
-  return next(rendezvous)
-
-
-def future_stream_in_value_out(
-    front, name, payload_iterator, timeout, trace_id, pool):
-  """Services a stream-in value-out servicer method by returning a Future."""
-  rendezvous = _control.Rendezvous()
-  subscription = _rendezvous_subscription(rendezvous)
-  operation = front.operate(name, None, False, timeout, subscription, trace_id)
-  operation.context.add_termination_callback(rendezvous.set_outcome)
-  pool.submit(
-      callable_util.with_exceptions_logged(
-          _control.pipe_iterator_to_consumer, _ITERATOR_EXCEPTION_LOG_MESSAGE),
-      payload_iterator, operation.consumer, lambda: True, True)
-  operation_future = _OperationFuture(rendezvous, operation)
-  operation.context.add_termination_callback(
-      operation_future.on_operation_termination)
-  return operation_future
-
-
-def inline_stream_in_stream_out(
-    front, name, payload_iterator, timeout, trace_id, pool):
-  """Services a stream-in stream-out servicer method."""
-  rendezvous = _control.Rendezvous()
-  subscription = _rendezvous_subscription(rendezvous)
-  operation = front.operate(name, None, False, timeout, subscription, trace_id)
-  operation.context.add_termination_callback(rendezvous.set_outcome)
-  pool.submit(
-      callable_util.with_exceptions_logged(
-          _control.pipe_iterator_to_consumer, _ITERATOR_EXCEPTION_LOG_MESSAGE),
-      payload_iterator, operation.consumer, lambda: True, True)
-  return _OperationCancellableIterator(rendezvous, operation)
-
-
-def event_value_in_value_out(
-    front, name, payload, completion_callback, abortion_callback, timeout,
-    trace_id):
-  subscription = _unary_event_subscription(
-      completion_callback, abortion_callback)
-  operation = front.operate(
-      name, payload, True, timeout, subscription, trace_id)
-  return _Call(operation)
-
-
-def event_value_in_stream_out(
-    front, name, payload, result_payload_consumer, abortion_callback, timeout,
-    trace_id):
-  subscription = _stream_event_subscription(
-      result_payload_consumer, abortion_callback)
-  operation = front.operate(
-      name, payload, True, timeout, subscription, trace_id)
-  return _Call(operation)
-
-
-def event_stream_in_value_out(
-    front, name, completion_callback, abortion_callback, timeout, trace_id):
-  subscription = _unary_event_subscription(
-      completion_callback, abortion_callback)
-  operation = front.operate(name, None, False, timeout, subscription, trace_id)
-  return _Call(operation), operation.consumer
-
-
-def event_stream_in_stream_out(
-    front, name, result_payload_consumer, abortion_callback, timeout, trace_id):
-  subscription = _stream_event_subscription(
-      result_payload_consumer, abortion_callback)
-  operation = front.operate(name, None, False, timeout, subscription, trace_id)
-  return _Call(operation), operation.consumer
diff --git a/src/python/grpcio/grpc/framework/face/_control.py b/src/python/grpcio/grpc/framework/face/_control.py
deleted file mode 100644
index 539615e..0000000
--- a/src/python/grpcio/grpc/framework/face/_control.py
+++ /dev/null
@@ -1,201 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""State and behavior for translating between sync and async control flow."""
-
-import threading
-
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.face import exceptions
-from grpc.framework.face import interfaces
-from grpc.framework.foundation import abandonment
-from grpc.framework.foundation import stream
-
-INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Face) Internal Error! :-('
-
-_OPERATION_OUTCOME_TO_RPC_ABORTION = {
-    base_interfaces.Outcome.CANCELLED: interfaces.Abortion.CANCELLED,
-    base_interfaces.Outcome.EXPIRED: interfaces.Abortion.EXPIRED,
-    base_interfaces.Outcome.RECEPTION_FAILURE:
-        interfaces.Abortion.NETWORK_FAILURE,
-    base_interfaces.Outcome.TRANSMISSION_FAILURE:
-        interfaces.Abortion.NETWORK_FAILURE,
-    base_interfaces.Outcome.SERVICED_FAILURE:
-        interfaces.Abortion.SERVICED_FAILURE,
-    base_interfaces.Outcome.SERVICER_FAILURE:
-        interfaces.Abortion.SERVICER_FAILURE,
-}
-
-
-def _as_operation_termination_callback(rpc_abortion_callback):
-  def operation_termination_callback(operation_outcome):
-    rpc_abortion = _OPERATION_OUTCOME_TO_RPC_ABORTION.get(
-        operation_outcome, None)
-    if rpc_abortion is not None:
-      rpc_abortion_callback(rpc_abortion)
-  return operation_termination_callback
-
-
-def _abortion_outcome_to_exception(abortion_outcome):
-  if abortion_outcome == base_interfaces.Outcome.CANCELLED:
-    return exceptions.CancellationError()
-  elif abortion_outcome == base_interfaces.Outcome.EXPIRED:
-    return exceptions.ExpirationError()
-  elif abortion_outcome == base_interfaces.Outcome.SERVICER_FAILURE:
-    return exceptions.ServicerError()
-  elif abortion_outcome == base_interfaces.Outcome.SERVICED_FAILURE:
-    return exceptions.ServicedError()
-  else:
-    return exceptions.NetworkError()
-
-
-class UnaryConsumer(stream.Consumer):
-  """A stream.Consumer that should only ever be passed one value."""
-
-  def __init__(self, on_termination):
-    self._on_termination = on_termination
-    self._value = None
-
-  def consume(self, value):
-    self._value = value
-
-  def terminate(self):
-    self._on_termination(self._value)
-
-  def consume_and_terminate(self, value):
-    self._on_termination(value)
-
-
-class Rendezvous(stream.Consumer):
-  """A rendez-vous with stream.Consumer and iterator interfaces."""
-
-  def __init__(self):
-    self._condition = threading.Condition()
-    self._values = []
-    self._values_completed = False
-    self._abortion = None
-
-  def consume(self, value):
-    with self._condition:
-      self._values.append(value)
-      self._condition.notify()
-
-  def terminate(self):
-    with self._condition:
-      self._values_completed = True
-      self._condition.notify()
-
-  def consume_and_terminate(self, value):
-    with self._condition:
-      self._values.append(value)
-      self._values_completed = True
-      self._condition.notify()
-
-  def __iter__(self):
-    return self
-
-  def __next__(self):
-    return self.next()
-
-  def next(self):
-    with self._condition:
-      while ((self._abortion is None) and
-             (not self._values) and
-             (not self._values_completed)):
-        self._condition.wait()
-      if self._abortion is not None:
-        raise _abortion_outcome_to_exception(self._abortion)
-      elif self._values:
-        return self._values.pop(0)
-      elif self._values_completed:
-        raise StopIteration()
-      else:
-        raise AssertionError('Unreachable code reached!')
-
-  def set_outcome(self, outcome):
-    with self._condition:
-      if outcome is not base_interfaces.Outcome.COMPLETED:
-        self._abortion = outcome
-        self._condition.notify()
-
-
-class RpcContext(interfaces.RpcContext):
-  """A wrapped base_interfaces.OperationContext."""
-
-  def __init__(self, operation_context):
-    self._operation_context = operation_context
-
-  def is_active(self):
-    return self._operation_context.is_active()
-
-  def time_remaining(self):
-    return self._operation_context.time_remaining()
-
-  def add_abortion_callback(self, abortion_callback):
-    self._operation_context.add_termination_callback(
-        _as_operation_termination_callback(abortion_callback))
-
-
-def pipe_iterator_to_consumer(iterator, consumer, active, terminate):
-  """Pipes values emitted from an iterator to a stream.Consumer.
-
-  Args:
-    iterator: An iterator from which values will be emitted.
-    consumer: A stream.Consumer to which values will be passed.
-    active: A no-argument callable that returns True if the work being done by
-      this function is still valid and should not be abandoned and False if the
-      work being done by this function should be abandoned.
-    terminate: A boolean indicating whether or not this function should
-      terminate the given consumer after passing to it all values emitted by the
-      given iterator.
-
-  Raises:
-    abandonment.Abandoned: If this function quits early after seeing False
-      returned by the active function passed to it.
-    Exception: This function raises whatever exceptions are raised by iterating
-      over the given iterator.
-  """
-  for element in iterator:
-    if not active():
-      raise abandonment.Abandoned()
-
-    consumer.consume(element)
-
-    if not active():
-      raise abandonment.Abandoned()
-  if terminate:
-    consumer.terminate()
-
-
-def abortion_outcome_to_exception(abortion_outcome):
-  return _abortion_outcome_to_exception(abortion_outcome)
-
-
-def as_operation_termination_callback(rpc_abortion_callback):
-  return _as_operation_termination_callback(rpc_abortion_callback)
diff --git a/src/python/grpcio/grpc/framework/face/_service.py b/src/python/grpcio/grpc/framework/face/_service.py
deleted file mode 100644
index cdf4133..0000000
--- a/src/python/grpcio/grpc/framework/face/_service.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Behaviors for servicing RPCs."""
-
-# base_interfaces and interfaces are referenced from specification in this
-# module.
-from grpc.framework.base import interfaces as base_interfaces  # pylint: disable=unused-import
-from grpc.framework.face import _control
-from grpc.framework.face import exceptions
-from grpc.framework.face import interfaces  # pylint: disable=unused-import
-from grpc.framework.foundation import abandonment
-from grpc.framework.foundation import callable_util
-from grpc.framework.foundation import stream
-from grpc.framework.foundation import stream_util
-
-
-class _ValueInStreamOutConsumer(stream.Consumer):
-  """A stream.Consumer that maps inputs one-to-many onto outputs."""
-
-  def __init__(self, behavior, context, downstream):
-    """Constructor.
-
-    Args:
-      behavior: A callable that takes a single value and an
-        interfaces.RpcContext and returns a generator of arbitrarily many
-        values.
-      context: An interfaces.RpcContext.
-      downstream: A stream.Consumer to which to pass the values generated by the
-        given behavior.
-    """
-    self._behavior = behavior
-    self._context = context
-    self._downstream = downstream
-
-  def consume(self, value):
-    _control.pipe_iterator_to_consumer(
-        self._behavior(value, self._context), self._downstream,
-        self._context.is_active, False)
-
-  def terminate(self):
-    self._downstream.terminate()
-
-  def consume_and_terminate(self, value):
-    _control.pipe_iterator_to_consumer(
-        self._behavior(value, self._context), self._downstream,
-        self._context.is_active, True)
-
-
-def _pool_wrap(behavior, operation_context):
-  """Wraps an operation-related behavior so that it may be called in a pool.
-
-  Args:
-    behavior: A callable related to carrying out an operation.
-    operation_context: A base_interfaces.OperationContext for the operation.
-
-  Returns:
-    A callable that when called carries out the behavior of the given callable
-      and handles whatever exceptions it raises appropriately.
-  """
-  def translation(*args):
-    try:
-      behavior(*args)
-    except (
-        abandonment.Abandoned,
-        exceptions.ExpirationError,
-        exceptions.CancellationError,
-        exceptions.ServicedError,
-        exceptions.NetworkError) as e:
-      if operation_context.is_active():
-        operation_context.fail(e)
-    except Exception as e:
-      operation_context.fail(e)
-  return callable_util.with_exceptions_logged(
-      translation, _control.INTERNAL_ERROR_LOG_MESSAGE)
-
-
-def adapt_inline_value_in_value_out(method):
-  def adaptation(response_consumer, operation_context):
-    rpc_context = _control.RpcContext(operation_context)
-    return stream_util.TransformingConsumer(
-        lambda request: method(request, rpc_context), response_consumer)
-  return adaptation
-
-
-def adapt_inline_value_in_stream_out(method):
-  def adaptation(response_consumer, operation_context):
-    rpc_context = _control.RpcContext(operation_context)
-    return _ValueInStreamOutConsumer(method, rpc_context, response_consumer)
-  return adaptation
-
-
-def adapt_inline_stream_in_value_out(method, pool):
-  def adaptation(response_consumer, operation_context):
-    rendezvous = _control.Rendezvous()
-    operation_context.add_termination_callback(rendezvous.set_outcome)
-    def in_pool_thread():
-      response_consumer.consume_and_terminate(
-          method(rendezvous, _control.RpcContext(operation_context)))
-    pool.submit(_pool_wrap(in_pool_thread, operation_context))
-    return rendezvous
-  return adaptation
-
-
-def adapt_inline_stream_in_stream_out(method, pool):
-  """Adapts an interfaces.InlineStreamInStreamOutMethod for use with Consumers.
-
-   RPCs may be serviced by calling the return value of this function, passing
-   request values to the stream.Consumer returned from that call, and receiving
-   response values from the stream.Consumer passed to that call.
-
-  Args:
-    method: An interfaces.InlineStreamInStreamOutMethod.
-    pool: A thread pool.
-
-  Returns:
-    A callable that takes a stream.Consumer and a
-      base_interfaces.OperationContext and returns a stream.Consumer.
-  """
-  def adaptation(response_consumer, operation_context):
-    rendezvous = _control.Rendezvous()
-    operation_context.add_termination_callback(rendezvous.set_outcome)
-    def in_pool_thread():
-      _control.pipe_iterator_to_consumer(
-          method(rendezvous, _control.RpcContext(operation_context)),
-          response_consumer, operation_context.is_active, True)
-    pool.submit(_pool_wrap(in_pool_thread, operation_context))
-    return rendezvous
-  return adaptation
-
-
-def adapt_event_value_in_value_out(method):
-  def adaptation(response_consumer, operation_context):
-    def on_payload(payload):
-      method(
-          payload, response_consumer.consume_and_terminate,
-          _control.RpcContext(operation_context))
-    return _control.UnaryConsumer(on_payload)
-  return adaptation
-
-
-def adapt_event_value_in_stream_out(method):
-  def adaptation(response_consumer, operation_context):
-    def on_payload(payload):
-      method(
-          payload, response_consumer, _control.RpcContext(operation_context))
-    return _control.UnaryConsumer(on_payload)
-  return adaptation
-
-
-def adapt_event_stream_in_value_out(method):
-  def adaptation(response_consumer, operation_context):
-    rpc_context = _control.RpcContext(operation_context)
-    return method(response_consumer.consume_and_terminate, rpc_context)
-  return adaptation
-
-
-def adapt_event_stream_in_stream_out(method):
-  def adaptation(response_consumer, operation_context):
-    return method(response_consumer, _control.RpcContext(operation_context))
-  return adaptation
diff --git a/src/python/grpcio/grpc/framework/face/demonstration.py b/src/python/grpcio/grpc/framework/face/demonstration.py
deleted file mode 100644
index f6b4b60..0000000
--- a/src/python/grpcio/grpc/framework/face/demonstration.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Demonstration-suitable implementation of the face layer of RPC Framework."""
-
-from grpc.framework.base import util as _base_util
-from grpc.framework.base import implementations as _base_implementations
-from grpc.framework.face import implementations
-from grpc.framework.foundation import logging_pool
-
-_POOL_SIZE_LIMIT = 5
-
-_MAXIMUM_TIMEOUT = 90
-
-
-class LinkedPair(object):
-  """A Server and Stub that are linked to one another.
-
-  Attributes:
-    server: A Server.
-    stub: A Stub.
-  """
-
-  def shut_down(self):
-    """Shuts down this object and releases its resources."""
-    raise NotImplementedError()
-
-
-class _LinkedPair(LinkedPair):
-
-  def __init__(self, server, stub, front, back, pools):
-    self.server = server
-    self.stub = stub
-    self._front = front
-    self._back = back
-    self._pools = pools
-
-  def shut_down(self):
-    _base_util.wait_for_idle(self._front)
-    _base_util.wait_for_idle(self._back)
-
-    for pool in self._pools:
-      pool.shutdown(wait=True)
-
-
-def server_and_stub(
-    default_timeout,
-    inline_value_in_value_out_methods=None,
-    inline_value_in_stream_out_methods=None,
-    inline_stream_in_value_out_methods=None,
-    inline_stream_in_stream_out_methods=None,
-    event_value_in_value_out_methods=None,
-    event_value_in_stream_out_methods=None,
-    event_stream_in_value_out_methods=None,
-    event_stream_in_stream_out_methods=None,
-    multi_method=None):
-  """Creates a Server and Stub linked together for use."""
-  front_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  front_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  front_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  back_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  back_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  back_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  stub_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  pools = (
-      front_work_pool, front_transmission_pool, front_utility_pool,
-      back_work_pool, back_transmission_pool, back_utility_pool,
-      stub_pool)
-
-  servicer = implementations.servicer(
-      back_work_pool,
-      inline_value_in_value_out_methods=inline_value_in_value_out_methods,
-      inline_value_in_stream_out_methods=inline_value_in_stream_out_methods,
-      inline_stream_in_value_out_methods=inline_stream_in_value_out_methods,
-      inline_stream_in_stream_out_methods=inline_stream_in_stream_out_methods,
-      event_value_in_value_out_methods=event_value_in_value_out_methods,
-      event_value_in_stream_out_methods=event_value_in_stream_out_methods,
-      event_stream_in_value_out_methods=event_stream_in_value_out_methods,
-      event_stream_in_stream_out_methods=event_stream_in_stream_out_methods,
-      multi_method=multi_method)
-
-  front = _base_implementations.front_link(
-      front_work_pool, front_transmission_pool, front_utility_pool)
-  back = _base_implementations.back_link(
-      servicer, back_work_pool, back_transmission_pool, back_utility_pool,
-      default_timeout, _MAXIMUM_TIMEOUT)
-  front.join_rear_link(back)
-  back.join_fore_link(front)
-
-  stub = implementations.stub(front, stub_pool)
-
-  return _LinkedPair(implementations.server(), stub, front, back, pools)
diff --git a/src/python/grpcio/grpc/framework/face/exceptions.py b/src/python/grpcio/grpc/framework/face/exceptions.py
deleted file mode 100644
index f954556..0000000
--- a/src/python/grpcio/grpc/framework/face/exceptions.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Exceptions used in the Face layer of RPC Framework."""
-
-import abc
-
-import six
-
-
-class NoSuchMethodError(Exception):
-  """Raised by customer code to indicate an unrecognized RPC method name.
-
-  Attributes:
-    name: The unrecognized name.
-  """
-
-  def __init__(self, name):
-    """Constructor.
-
-    Args:
-      name: The unrecognized RPC method name.
-    """
-    super(NoSuchMethodError, self).__init__()
-    self.name = name
-
-
-class RpcError(six.with_metaclass(abc.ABCMeta, Exception)):
-  """Common super type for all exceptions raised by the Face layer.
-
-  Only RPC Framework should instantiate and raise these exceptions.
-  """
-
-
-class CancellationError(RpcError):
-  """Indicates that an RPC has been cancelled."""
-
-
-class ExpirationError(RpcError):
-  """Indicates that an RPC has expired ("timed out")."""
-
-
-class NetworkError(RpcError):
-  """Indicates that some error occurred on the network."""
-
-
-class ServicedError(RpcError):
-  """Indicates that the Serviced failed in the course of an RPC."""
-
-
-class ServicerError(RpcError):
-  """Indicates that the Servicer failed in the course of servicing an RPC."""
diff --git a/src/python/grpcio/grpc/framework/face/implementations.py b/src/python/grpcio/grpc/framework/face/implementations.py
deleted file mode 100644
index 96055b4..0000000
--- a/src/python/grpcio/grpc/framework/face/implementations.py
+++ /dev/null
@@ -1,320 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Entry points into the Face layer of RPC Framework."""
-
-import six
-
-from grpc.framework.common import cardinality
-from grpc.framework.common import style
-from grpc.framework.base import exceptions as _base_exceptions
-from grpc.framework.base import interfaces as base_interfaces
-from grpc.framework.face import _calls
-from grpc.framework.face import _service
-from grpc.framework.face import exceptions
-from grpc.framework.face import interfaces
-
-
-class _BaseServicer(base_interfaces.Servicer):
-
-  def __init__(self, methods, multi_method):
-    self._methods = methods
-    self._multi_method = multi_method
-
-  def service(self, name, context, output_consumer):
-    method = self._methods.get(name, None)
-    if method is not None:
-      return method(output_consumer, context)
-    elif self._multi_method is not None:
-      try:
-        return self._multi_method.service(name, output_consumer, context)
-      except exceptions.NoSuchMethodError:
-        raise _base_exceptions.NoSuchMethodError()
-    else:
-      raise _base_exceptions.NoSuchMethodError()
-
-
-class _UnaryUnaryMultiCallable(interfaces.UnaryUnaryMultiCallable):
-
-  def __init__(self, front, name):
-    self._front = front
-    self._name = name
-
-  def __call__(self, request, timeout):
-    return _calls.blocking_value_in_value_out(
-        self._front, self._name, request, timeout, 'unused trace ID')
-
-  def future(self, request, timeout):
-    return _calls.future_value_in_value_out(
-        self._front, self._name, request, timeout, 'unused trace ID')
-
-  def event(self, request, response_callback, abortion_callback, timeout):
-    return _calls.event_value_in_value_out(
-        self._front, self._name, request, response_callback, abortion_callback,
-        timeout, 'unused trace ID')
-
-
-class _UnaryStreamMultiCallable(interfaces.UnaryStreamMultiCallable):
-
-  def __init__(self, front, name):
-    self._front = front
-    self._name = name
-
-  def __call__(self, request, timeout):
-    return _calls.inline_value_in_stream_out(
-        self._front, self._name, request, timeout, 'unused trace ID')
-
-  def event(self, request, response_consumer, abortion_callback, timeout):
-    return _calls.event_value_in_stream_out(
-        self._front, self._name, request, response_consumer, abortion_callback,
-        timeout, 'unused trace ID')
-
-
-class _StreamUnaryMultiCallable(interfaces.StreamUnaryMultiCallable):
-
-  def __init__(self, front, name, pool):
-    self._front = front
-    self._name = name
-    self._pool = pool
-
-  def __call__(self, request_iterator, timeout):
-    return _calls.blocking_stream_in_value_out(
-        self._front, self._name, request_iterator, timeout, 'unused trace ID')
-
-  def future(self, request_iterator, timeout):
-    return _calls.future_stream_in_value_out(
-        self._front, self._name, request_iterator, timeout, 'unused trace ID',
-        self._pool)
-
-  def event(self, response_callback, abortion_callback, timeout):
-    return _calls.event_stream_in_value_out(
-        self._front, self._name, response_callback, abortion_callback, timeout,
-        'unused trace ID')
-
-
-class _StreamStreamMultiCallable(interfaces.StreamStreamMultiCallable):
-
-  def __init__(self, front, name, pool):
-    self._front = front
-    self._name = name
-    self._pool = pool
-
-  def __call__(self, request_iterator, timeout):
-    return _calls.inline_stream_in_stream_out(
-        self._front, self._name, request_iterator, timeout, 'unused trace ID',
-        self._pool)
-
-  def event(self, response_consumer, abortion_callback, timeout):
-    return _calls.event_stream_in_stream_out(
-        self._front, self._name, response_consumer, abortion_callback, timeout,
-        'unused trace ID')
-
-
-class _GenericStub(interfaces.GenericStub):
-  """An interfaces.GenericStub implementation."""
-
-  def __init__(self, front, pool):
-    self._front = front
-    self._pool = pool
-
-  def blocking_value_in_value_out(self, name, request, timeout):
-    return _calls.blocking_value_in_value_out(
-        self._front, name, request, timeout, 'unused trace ID')
-
-  def future_value_in_value_out(self, name, request, timeout):
-    return _calls.future_value_in_value_out(
-        self._front, name, request, timeout, 'unused trace ID')
-
-  def inline_value_in_stream_out(self, name, request, timeout):
-    return _calls.inline_value_in_stream_out(
-        self._front, name, request, timeout, 'unused trace ID')
-
-  def blocking_stream_in_value_out(self, name, request_iterator, timeout):
-    return _calls.blocking_stream_in_value_out(
-        self._front, name, request_iterator, timeout, 'unused trace ID')
-
-  def future_stream_in_value_out(self, name, request_iterator, timeout):
-    return _calls.future_stream_in_value_out(
-        self._front, name, request_iterator, timeout, 'unused trace ID',
-        self._pool)
-
-  def inline_stream_in_stream_out(self, name, request_iterator, timeout):
-    return _calls.inline_stream_in_stream_out(
-        self._front, name, request_iterator, timeout, 'unused trace ID',
-        self._pool)
-
-  def event_value_in_value_out(
-      self, name, request, response_callback, abortion_callback, timeout):
-    return _calls.event_value_in_value_out(
-        self._front, name, request, response_callback, abortion_callback,
-        timeout, 'unused trace ID')
-
-  def event_value_in_stream_out(
-      self, name, request, response_consumer, abortion_callback, timeout):
-    return _calls.event_value_in_stream_out(
-        self._front, name, request, response_consumer, abortion_callback,
-        timeout, 'unused trace ID')
-
-  def event_stream_in_value_out(
-      self, name, response_callback, abortion_callback, timeout):
-    return _calls.event_stream_in_value_out(
-        self._front, name, response_callback, abortion_callback, timeout,
-        'unused trace ID')
-
-  def event_stream_in_stream_out(
-      self, name, response_consumer, abortion_callback, timeout):
-    return _calls.event_stream_in_stream_out(
-        self._front, name, response_consumer, abortion_callback, timeout,
-        'unused trace ID')
-
-  def unary_unary_multi_callable(self, name):
-    return _UnaryUnaryMultiCallable(self._front, name)
-
-  def unary_stream_multi_callable(self, name):
-    return _UnaryStreamMultiCallable(self._front, name)
-
-  def stream_unary_multi_callable(self, name):
-    return _StreamUnaryMultiCallable(self._front, name, self._pool)
-
-  def stream_stream_multi_callable(self, name):
-    return _StreamStreamMultiCallable(self._front, name, self._pool)
-
-
-class _DynamicStub(interfaces.DynamicStub):
-  """An interfaces.DynamicStub implementation."""
-
-  def __init__(self, cardinalities, front, pool):
-    self._cardinalities = cardinalities
-    self._front = front
-    self._pool = pool
-
-  def __getattr__(self, attr):
-    method_cardinality = self._cardinalities.get(attr)
-    if method_cardinality is cardinality.Cardinality.UNARY_UNARY:
-      return _UnaryUnaryMultiCallable(self._front, attr)
-    elif method_cardinality is cardinality.Cardinality.UNARY_STREAM:
-      return _UnaryStreamMultiCallable(self._front, attr)
-    elif method_cardinality is cardinality.Cardinality.STREAM_UNARY:
-      return _StreamUnaryMultiCallable(self._front, attr, self._pool)
-    elif method_cardinality is cardinality.Cardinality.STREAM_STREAM:
-      return _StreamStreamMultiCallable(self._front, attr, self._pool)
-    else:
-      raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr)
-
-
-def _adapt_method_implementations(method_implementations, pool):
-  adapted_implementations = {}
-  for name, method_implementation in six.iteritems(method_implementations):
-    if method_implementation.style is style.Service.INLINE:
-      if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
-        adapted_implementations[name] = _service.adapt_inline_value_in_value_out(
-            method_implementation.unary_unary_inline)
-      elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
-        adapted_implementations[name] = _service.adapt_inline_value_in_stream_out(
-            method_implementation.unary_stream_inline)
-      elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
-        adapted_implementations[name] = _service.adapt_inline_stream_in_value_out(
-            method_implementation.stream_unary_inline, pool)
-      elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
-        adapted_implementations[name] = _service.adapt_inline_stream_in_stream_out(
-            method_implementation.stream_stream_inline, pool)
-    elif method_implementation.style is style.Service.EVENT:
-      if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY:
-        adapted_implementations[name] = _service.adapt_event_value_in_value_out(
-            method_implementation.unary_unary_event)
-      elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM:
-        adapted_implementations[name] = _service.adapt_event_value_in_stream_out(
-            method_implementation.unary_stream_event)
-      elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY:
-        adapted_implementations[name] = _service.adapt_event_stream_in_value_out(
-            method_implementation.stream_unary_event)
-      elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM:
-        adapted_implementations[name] = _service.adapt_event_stream_in_stream_out(
-            method_implementation.stream_stream_event)
-  return adapted_implementations
-
-
-def servicer(pool, method_implementations, multi_method_implementation):
-  """Creates a base_interfaces.Servicer.
-
-  It is guaranteed that any passed interfaces.MultiMethodImplementation will
-  only be called to service an RPC if there is no
-  interfaces.MethodImplementation for the RPC method in the passed
-  method_implementations dictionary.
-
-  Args:
-    pool: A thread pool.
-    method_implementations: A dictionary from RPC method name to
-      interfaces.MethodImplementation object to be used to service the named
-      RPC method.
-    multi_method_implementation: An interfaces.MultiMethodImplementation to be
-      used to service any RPCs not serviced by the
-      interfaces.MethodImplementations given in the method_implementations
-      dictionary, or None.
-
-  Returns:
-    A base_interfaces.Servicer that services RPCs via the given implementations.
-  """
-  adapted_implementations = _adapt_method_implementations(
-      method_implementations, pool)
-  return _BaseServicer(adapted_implementations, multi_method_implementation)
-
-
-def generic_stub(front, pool):
-  """Creates an interfaces.GenericStub.
-
-  Args:
-    front: A base_interfaces.Front.
-    pool: A futures.ThreadPoolExecutor.
-
-  Returns:
-    An interfaces.GenericStub that performs RPCs via the given
-      base_interfaces.Front.
-  """
-  return _GenericStub(front, pool)
-
-
-def dynamic_stub(cardinalities, front, pool, prefix):
-  """Creates an interfaces.DynamicStub.
-
-  Args:
-    cardinalities: A dict from RPC method name to cardinality.Cardinality
-      value identifying the cardinality of every RPC method to be supported by
-      the created interfaces.DynamicStub.
-    front: A base_interfaces.Front.
-    pool: A futures.ThreadPoolExecutor.
-    prefix: A string to prepend when mapping requested attribute name to RPC
-      method name during attribute access on the created
-      interfaces.DynamicStub.
-
-  Returns:
-    An interfaces.DynamicStub that performs RPCs via the given
-      base_interfaces.Front.
-  """
-  return _DynamicStub(cardinalities, front, pool)
diff --git a/src/python/grpcio/grpc/framework/face/interfaces.py b/src/python/grpcio/grpc/framework/face/interfaces.py
deleted file mode 100644
index e9a25c1..0000000
--- a/src/python/grpcio/grpc/framework/face/interfaces.py
+++ /dev/null
@@ -1,634 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Interfaces for the face layer of RPC Framework."""
-
-import abc
-import enum
-
-import six
-
-# cardinality, style, exceptions, abandonment, future, and stream are
-# referenced from specification in this module.
-from grpc.framework.common import cardinality  # pylint: disable=unused-import
-from grpc.framework.common import style  # pylint: disable=unused-import
-from grpc.framework.face import exceptions  # pylint: disable=unused-import
-from grpc.framework.foundation import abandonment  # pylint: disable=unused-import
-from grpc.framework.foundation import future  # pylint: disable=unused-import
-from grpc.framework.foundation import stream  # pylint: disable=unused-import
-
-
-@enum.unique
-class Abortion(enum.Enum):
-  """Categories of RPC abortion."""
-  CANCELLED = 'cancelled'
-  EXPIRED = 'expired'
-  NETWORK_FAILURE = 'network failure'
-  SERVICED_FAILURE = 'serviced failure'
-  SERVICER_FAILURE = 'servicer failure'
-
-
-class CancellableIterator(six.with_metaclass(abc.ABCMeta)):
-  """Implements the Iterator protocol and affords a cancel method."""
-
-  @abc.abstractmethod
-  def __iter__(self):
-    """Returns the self object in accordance with the Iterator protocol."""
-    raise NotImplementedError()
-
-  def __next__(self):
-    return self.next()
-
-  @abc.abstractmethod
-  def next(self):
-    """Returns a value or raises StopIteration per the Iterator protocol."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def cancel(self):
-    """Requests cancellation of whatever computation underlies this iterator."""
-    raise NotImplementedError()
-
-
-class RpcContext(six.with_metaclass(abc.ABCMeta)):
-  """Provides RPC-related information and action."""
-
-  @abc.abstractmethod
-  def is_active(self):
-    """Describes whether the RPC is active or has terminated."""
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def time_remaining(self):
-    """Describes the length of allowed time remaining for the RPC.
-
-    Returns:
-      A nonnegative float indicating the length of allowed time in seconds
-      remaining for the RPC to complete before it is considered to have timed
-      out.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def add_abortion_callback(self, abortion_callback):
-    """Registers a callback to be called if the RPC is aborted.
-
-    Args:
-      abortion_callback: A callable to be called and passed an Abortion value
-        in the event of RPC abortion.
-    """
-    raise NotImplementedError()
-
-
-class Call(six.with_metaclass(abc.ABCMeta)):
-  """Invocation-side representation of an RPC.
-
-  Attributes:
-    context: An RpcContext affording information about the RPC.
-  """
-
-  @abc.abstractmethod
-  def cancel(self):
-    """Requests cancellation of the RPC."""
-    raise NotImplementedError()
-
-
-class UnaryUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
-  """Affords invoking a unary-unary RPC in any call style."""
-
-  @abc.abstractmethod
-  def __call__(self, request, timeout):
-    """Synchronously invokes the underlying RPC.
-
-    Args:
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      The response value for the RPC.
-
-    Raises:
-      exceptions.RpcError: Indicating that the RPC was aborted.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def future(self, request, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-    Args:
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A future.Future representing the RPC. In the event of RPC completion, the
-        returned Future's result value will be the response value of the RPC.
-        In the event of RPC abortion, the returned Future's exception value
-        will be an exceptions.RpcError.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event(self, request, response_callback, abortion_callback, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-    Args:
-      request: The request value for the RPC.
-      response_callback: A callback to be called to accept the restponse value
-        of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A Call object for the RPC.
-    """
-    raise NotImplementedError()
-
-
-class UnaryStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
-  """Affords invoking a unary-stream RPC in any call style."""
-
-  @abc.abstractmethod
-  def __call__(self, request, timeout):
-    """Synchronously invokes the underlying RPC.
-
-    Args:
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A CancellableIterator that yields the response values of the RPC and
-        affords RPC cancellation. Drawing response values from the returned
-        CancellableIterator may raise exceptions.RpcError indicating abortion
-        of the RPC.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event(self, request, response_consumer, abortion_callback, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-    Args:
-      request: The request value for the RPC.
-      response_consumer: A stream.Consumer to be called to accept the restponse
-        values of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A Call object for the RPC.
-    """
-    raise NotImplementedError()
-
-
-class StreamUnaryMultiCallable(six.with_metaclass(abc.ABCMeta)):
-  """Affords invoking a stream-unary RPC in any call style."""
-
-  @abc.abstractmethod
-  def __call__(self, request_iterator, timeout):
-    """Synchronously invokes the underlying RPC.
-
-    Args:
-      request_iterator: An iterator that yields request values for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      The response value for the RPC.
-
-    Raises:
-      exceptions.RpcError: Indicating that the RPC was aborted.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def future(self, request_iterator, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-    Args:
-      request_iterator: An iterator that yields request values for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A future.Future representing the RPC. In the event of RPC completion, the
-        returned Future's result value will be the response value of the RPC.
-        In the event of RPC abortion, the returned Future's exception value
-        will be an exceptions.RpcError.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event(self, response_callback, abortion_callback, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-    Args:
-      request: The request value for the RPC.
-      response_callback: A callback to be called to accept the restponse value
-        of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A pair of a Call object for the RPC and a stream.Consumer to which the
-        request values of the RPC should be passed.
-    """
-    raise NotImplementedError()
-
-
-class StreamStreamMultiCallable(six.with_metaclass(abc.ABCMeta)):
-  """Affords invoking a stream-stream RPC in any call style."""
-
-  @abc.abstractmethod
-  def __call__(self, request_iterator, timeout):
-    """Synchronously invokes the underlying RPC.
-
-    Args:
-      request_iterator: An iterator that yields request values for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A CancellableIterator that yields the response values of the RPC and
-        affords RPC cancellation. Drawing response values from the returned
-        CancellableIterator may raise exceptions.RpcError indicating abortion
-        of the RPC.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event(self, response_consumer, abortion_callback, timeout):
-    """Asynchronously invokes the underlying RPC.
-
-l    Args:
-      response_consumer: A stream.Consumer to be called to accept the restponse
-        values of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A pair of a Call object for the RPC and a stream.Consumer to which the
-        request values of the RPC should be passed.
-    """
-    raise NotImplementedError()
-
-
-class MethodImplementation(six.with_metaclass(abc.ABCMeta)):
-  """A sum type that describes an RPC method implementation.
-
-  Attributes:
-    cardinality: A cardinality.Cardinality value.
-    style: A style.Service value.
-    unary_unary_inline: The implementation of the RPC method as a callable
-      value that takes a request value and an RpcContext object and returns a
-      response value. Only non-None if cardinality is
-      cardinality.Cardinality.UNARY_UNARY and style is style.Service.INLINE.
-    unary_stream_inline: The implementation of the RPC method as a callable
-      value that takes a request value and an RpcContext object and returns an
-      iterator of response values. Only non-None if cardinality is
-      cardinality.Cardinality.UNARY_STREAM and style is style.Service.INLINE.
-    stream_unary_inline: The implementation of the RPC method as a callable
-      value that takes an iterator of request values and an RpcContext object
-      and returns a response value. Only non-None if cardinality is
-      cardinality.Cardinality.STREAM_UNARY and style is style.Service.INLINE.
-    stream_stream_inline: The implementation of the RPC method as a callable
-      value that takes an iterator of request values and an RpcContext object
-      and returns an iterator of response values. Only non-None if cardinality
-      is cardinality.Cardinality.STREAM_STREAM and style is
-      style.Service.INLINE.
-    unary_unary_event: The implementation of the RPC method as a callable value
-      that takes a request value, a response callback to which to pass the
-      response value of the RPC, and an RpcContext. Only non-None if
-      cardinality is cardinality.Cardinality.UNARY_UNARY and style is
-      style.Service.EVENT.
-    unary_stream_event: The implementation of the RPC method as a callable
-      value that takes a request value, a stream.Consumer to which to pass the
-      the response values of the RPC, and an RpcContext. Only non-None if
-      cardinality is cardinality.Cardinality.UNARY_STREAM and style is
-      style.Service.EVENT.
-    stream_unary_event: The implementation of the RPC method as a callable
-      value that takes a response callback to which to pass the response value
-      of the RPC and an RpcContext and returns a stream.Consumer to which the
-      request values of the RPC should be passed. Only non-None if cardinality
-      is cardinality.Cardinality.STREAM_UNARY and style is style.Service.EVENT.
-    stream_stream_event: The implementation of the RPC method as a callable
-      value that takes a stream.Consumer to which to pass the response values
-      of the RPC and an RpcContext and returns a stream.Consumer to which the
-      request values of the RPC should be passed. Only non-None if cardinality
-      is cardinality.Cardinality.STREAM_STREAM and style is
-      style.Service.EVENT.
-  """
-
-
-class MultiMethodImplementation(six.with_metaclass(abc.ABCMeta)):
-  """A general type able to service many RPC methods."""
-
-  @abc.abstractmethod
-  def service(self, name, response_consumer, context):
-    """Services an RPC.
-
-    Args:
-      name: The RPC method name.
-      response_consumer: A stream.Consumer to be called to accept the response
-        values of the RPC.
-      context: An RpcContext object.
-
-    Returns:
-      A stream.Consumer with which to accept the request values of the RPC. The
-        consumer returned from this method may or may not be invoked to
-        completion: in the case of RPC abortion, RPC Framework will simply stop
-        passing values to this object. Implementations must not assume that this
-        object will be called to completion of the request stream or even called
-        at all.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-      exceptions.NoSuchMethodError: If this MultiMethod does not recognize the
-        given RPC method name and is not able to service the RPC.
-    """
-    raise NotImplementedError()
-
-
-class GenericStub(six.with_metaclass(abc.ABCMeta)):
-  """Affords RPC methods to callers."""
-
-  @abc.abstractmethod
-  def blocking_value_in_value_out(self, name, request, timeout):
-    """Invokes a unary-request-unary-response RPC method.
-
-    This method blocks until either returning the response value of the RPC
-    (in the event of RPC completion) or raising an exception (in the event of
-    RPC abortion).
-
-    Args:
-      name: The RPC method name.
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      The response value for the RPC.
-
-    Raises:
-      exceptions.RpcError: Indicating that the RPC was aborted.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def future_value_in_value_out(self, name, request, timeout):
-    """Invokes a unary-request-unary-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A future.Future representing the RPC. In the event of RPC completion, the
-        returned Future will return an outcome indicating that the RPC returned
-        the response value of the RPC. In the event of RPC abortion, the
-        returned Future will return an outcome indicating that the RPC raised
-        an exceptions.RpcError.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def inline_value_in_stream_out(self, name, request, timeout):
-    """Invokes a unary-request-stream-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      request: The request value for the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A CancellableIterator that yields the response values of the RPC and
-        affords RPC cancellation. Drawing response values from the returned
-        CancellableIterator may raise exceptions.RpcError indicating abortion of
-        the RPC.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def blocking_stream_in_value_out(self, name, request_iterator, timeout):
-    """Invokes a stream-request-unary-response RPC method.
-
-    This method blocks until either returning the response value of the RPC
-    (in the event of RPC completion) or raising an exception (in the event of
-    RPC abortion).
-
-    Args:
-      name: The RPC method name.
-      request_iterator: An iterator that yields the request values of the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      The response value for the RPC.
-
-    Raises:
-      exceptions.RpcError: Indicating that the RPC was aborted.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def future_stream_in_value_out(self, name, request_iterator, timeout):
-    """Invokes a stream-request-unary-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      request_iterator: An iterator that yields the request values of the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A future.Future representing the RPC. In the event of RPC completion, the
-        returned Future will return an outcome indicating that the RPC returned
-        the response value of the RPC. In the event of RPC abortion, the
-        returned Future will return an outcome indicating that the RPC raised
-        an exceptions.RpcError.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def inline_stream_in_stream_out(self, name, request_iterator, timeout):
-    """Invokes a stream-request-stream-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      request_iterator: An iterator that yields the request values of the RPC.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A CancellableIterator that yields the response values of the RPC and
-        affords RPC cancellation. Drawing response values from the returned
-        CancellableIterator may raise exceptions.RpcError indicating abortion of
-        the RPC.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event_value_in_value_out(
-      self, name, request, response_callback, abortion_callback, timeout):
-    """Event-driven invocation of a unary-request-unary-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      request: The request value for the RPC.
-      response_callback: A callback to be called to accept the response value
-        of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A Call object for the RPC.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event_value_in_stream_out(
-      self, name, request, response_consumer, abortion_callback, timeout):
-    """Event-driven invocation of a unary-request-stream-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      request: The request value for the RPC.
-      response_consumer: A stream.Consumer to be called to accept the response
-        values of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A Call object for the RPC.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event_stream_in_value_out(
-      self, name, response_callback, abortion_callback, timeout):
-    """Event-driven invocation of a unary-request-unary-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      response_callback: A callback to be called to accept the response value
-        of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A pair of a Call object for the RPC and a stream.Consumer to which the
-        request values of the RPC should be passed.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def event_stream_in_stream_out(
-      self, name, response_consumer, abortion_callback, timeout):
-    """Event-driven invocation of a unary-request-stream-response RPC method.
-
-    Args:
-      name: The RPC method name.
-      response_consumer: A stream.Consumer to be called to accept the response
-        values of the RPC.
-      abortion_callback: A callback to be called and passed an Abortion value
-        in the event of RPC abortion.
-      timeout: A duration of time in seconds to allow for the RPC.
-
-    Returns:
-      A pair of a Call object for the RPC and a stream.Consumer to which the
-        request values of the RPC should be passed.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def unary_unary_multi_callable(self, name):
-    """Creates a UnaryUnaryMultiCallable for a unary-unary RPC method.
-
-    Args:
-      name: The RPC method name.
-
-    Returns:
-      A UnaryUnaryMultiCallable value for the named unary-unary RPC method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def unary_stream_multi_callable(self, name):
-    """Creates a UnaryStreamMultiCallable for a unary-stream RPC method.
-
-    Args:
-      name: The RPC method name.
-
-    Returns:
-      A UnaryStreamMultiCallable value for the name unary-stream RPC method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def stream_unary_multi_callable(self, name):
-    """Creates a StreamUnaryMultiCallable for a stream-unary RPC method.
-
-    Args:
-      name: The RPC method name.
-
-    Returns:
-      A StreamUnaryMultiCallable value for the named stream-unary RPC method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def stream_stream_multi_callable(self, name):
-    """Creates a StreamStreamMultiCallable for a stream-stream RPC method.
-
-    Args:
-      name: The RPC method name.
-
-    Returns:
-      A StreamStreamMultiCallable value for the named stream-stream RPC method.
-    """
-    raise NotImplementedError()
-
-
-class DynamicStub(six.with_metaclass(abc.ABCMeta)):
-  """A stub with RPC-method-bound multi-callable attributes.
-
-  Instances of this type responsd to attribute access as follows: if the
-  requested attribute is the name of a unary-unary RPC method, the value of the
-  attribute will be a UnaryUnaryMultiCallable with which to invoke the RPC
-  method; if the requested attribute is the name of a unary-stream RPC method,
-  the value of the attribute will be a UnaryStreamMultiCallable with which to
-  invoke the RPC method; if the requested attribute is the name of a
-  stream-unary RPC method, the value of the attribute will be a
-  StreamUnaryMultiCallable with which to invoke the RPC method; and if the
-  requested attribute is the name of a stream-stream RPC method, the value of
-  the attribute will be a StreamStreamMultiCallable with which to invoke the
-  RPC method.
-  """
diff --git a/src/python/grpcio/grpc/framework/face/utilities.py b/src/python/grpcio/grpc/framework/face/utilities.py
deleted file mode 100644
index a63fe8c..0000000
--- a/src/python/grpcio/grpc/framework/face/utilities.py
+++ /dev/null
@@ -1,177 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Utilities for RPC framework's face layer."""
-
-import collections
-
-from grpc.framework.common import cardinality
-from grpc.framework.common import style
-from grpc.framework.face import interfaces
-from grpc.framework.foundation import stream
-
-
-class _MethodImplementation(
-    interfaces.MethodImplementation,
-    collections.namedtuple(
-        '_MethodImplementation',
-        ['cardinality', 'style', 'unary_unary_inline', 'unary_stream_inline',
-         'stream_unary_inline', 'stream_stream_inline', 'unary_unary_event',
-         'unary_stream_event', 'stream_unary_event', 'stream_stream_event',])):
-  pass
-
-
-def unary_unary_inline(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a unary-unary RPC method as a callable value
-      that takes a request value and an interfaces.RpcContext object and
-      returns a response value.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.UNARY_UNARY, style.Service.INLINE, behavior,
-      None, None, None, None, None, None, None)
-
-
-def unary_stream_inline(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a unary-stream RPC method as a callable
-      value that takes a request value and an interfaces.RpcContext object and
-      returns an iterator of response values.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.UNARY_STREAM, style.Service.INLINE, None,
-      behavior, None, None, None, None, None, None)
-
-
-def stream_unary_inline(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a stream-unary RPC method as a callable
-      value that takes an iterator of request values and an
-      interfaces.RpcContext object and returns a response value.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.STREAM_UNARY, style.Service.INLINE, None, None,
-      behavior, None, None, None, None, None)
-
-
-def stream_stream_inline(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a stream-stream RPC method as a callable
-      value that takes an iterator of request values and an
-      interfaces.RpcContext object and returns an iterator of response values.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.STREAM_STREAM, style.Service.INLINE, None, None,
-      None, behavior, None, None, None, None)
-
-
-def unary_unary_event(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a unary-unary RPC method as a callable
-      value that takes a request value, a response callback to which to pass
-      the response value of the RPC, and an interfaces.RpcContext.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.UNARY_UNARY, style.Service.EVENT, None, None,
-      None, None, behavior, None, None, None)
-
-
-def unary_stream_event(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a unary-stream RPC method as a callable
-      value that takes a request value, a stream.Consumer to which to pass the
-      the response values of the RPC, and an interfaces.RpcContext.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.UNARY_STREAM, style.Service.EVENT, None, None,
-      None, None, None, behavior, None, None)
-
-
-def stream_unary_event(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a stream-unary RPC method as a callable
-      value that takes a response callback to which to pass the response value
-      of the RPC and an interfaces.RpcContext and returns a stream.Consumer to
-      which the request values of the RPC should be passed.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.STREAM_UNARY, style.Service.EVENT, None, None,
-      None, None, None, None, behavior, None)
-
-
-def stream_stream_event(behavior):
-  """Creates an interfaces.MethodImplementation for the given behavior.
-
-  Args:
-    behavior: The implementation of a stream-stream RPC method as a callable
-      value that takes a stream.Consumer to which to pass the response values
-      of the RPC and an interfaces.RpcContext and returns a stream.Consumer to
-      which the request values of the RPC should be passed.
-
-  Returns:
-    An interfaces.MethodImplementation derived from the given behavior.
-  """
-  return _MethodImplementation(
-      cardinality.Cardinality.STREAM_STREAM, style.Service.EVENT, None, None,
-      None, None, None, None, None, behavior)
diff --git a/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
index 6fba3d4..3dc3042 100644
--- a/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
+++ b/src/python/grpcio/tests/protoc_plugin/beta_python_plugin_test.py
@@ -45,6 +45,7 @@
 from six import moves
 
 from grpc.beta import implementations
+from grpc.beta import interfaces
 from grpc.framework.foundation import future
 from grpc.framework.interfaces.face import face
 from tests.unit.framework.common import test_constants
@@ -178,6 +179,36 @@
   server.stop(0)
 
 
+@contextlib.contextmanager
+def _CreateIncompleteService(test_pb2):
+  """Provides a servicer backend that fails to implement methods and its stub.
+
+  The servicer is just the implementation of the actual servicer passed to the
+  face player of the python RPC implementation; the two are detached.
+
+  Args:
+    test_pb2: The test_pb2 module generated by this test.
+
+  Yields:
+    A (servicer_methods, stub) pair where servicer_methods is the back-end of
+      the service bound to the stub and and stub is the stub on which to invoke
+      RPCs.
+  """
+  servicer_methods = _ServicerMethods(test_pb2)
+
+  class Servicer(getattr(test_pb2, SERVICER_IDENTIFIER)):
+    pass
+
+  servicer = Servicer()
+  server = getattr(test_pb2, SERVER_FACTORY_IDENTIFIER)(servicer)
+  port = server.add_insecure_port('[::]:0')
+  server.start()
+  channel = implementations.insecure_channel('localhost', port)
+  stub = getattr(test_pb2, STUB_FACTORY_IDENTIFIER)(channel)
+  yield servicer_methods, stub
+  server.stop(0)
+
+
 def _streaming_input_request_iterator(test_pb2):
   for _ in range(3):
     request = test_pb2.StreamingInputCallRequest()
@@ -264,6 +295,16 @@
     with _CreateService(test_pb2) as (servicer, stub):
       request = test_pb2.SimpleRequest(response_size=13)
 
+  def testIncompleteServicer(self):
+    import protoc_plugin_test_pb2 as test_pb2
+    moves.reload_module(test_pb2)
+    with _CreateIncompleteService(test_pb2) as (servicer, stub):
+      request = test_pb2.SimpleRequest(response_size=13)
+      try:
+        response = stub.UnaryCall(request, test_constants.LONG_TIMEOUT)
+      except face.AbortionError as error:
+        self.assertEqual(interfaces.StatusCode.UNIMPLEMENTED, error.code)
+
   def testUnaryCall(self):
     import protoc_plugin_test_pb2 as test_pb2  # pylint: disable=g-import-not-at-top
     moves.reload_module(test_pb2)
diff --git a/src/python/grpcio/tests/unit/framework/face/__init__.py b/src/python/grpcio/tests/qps/__init__.py
similarity index 97%
rename from src/python/grpcio/tests/unit/framework/face/__init__.py
rename to src/python/grpcio/tests/qps/__init__.py
index 7086519..100a624 100644
--- a/src/python/grpcio/tests/unit/framework/face/__init__.py
+++ b/src/python/grpcio/tests/qps/__init__.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -26,5 +26,3 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
diff --git a/src/python/grpcio/tests/qps/benchmark_client.py b/src/python/grpcio/tests/qps/benchmark_client.py
new file mode 100644
index 0000000..eed0b0c
--- /dev/null
+++ b/src/python/grpcio/tests/qps/benchmark_client.py
@@ -0,0 +1,186 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Defines test client behaviors (UNARY/STREAMING) (SYNC/ASYNC)."""
+
+import abc
+import time
+try:
+  import Queue as queue  # Python 2.x
+except ImportError:
+  import queue  # Python 3
+
+from concurrent import futures
+
+from grpc.beta import implementations
+from src.proto.grpc.testing import messages_pb2
+from src.proto.grpc.testing import services_pb2
+from tests.unit import resources
+from tests.unit.beta import test_utilities
+
+_TIMEOUT = 60 * 60 * 24
+
+
+class BenchmarkClient:
+  """Benchmark client interface that exposes a non-blocking send_request()."""
+
+  __metaclass__ = abc.ABCMeta
+
+  def __init__(self, server, config, hist):
+    # Create the stub
+    host, port = server.split(':')
+    port = int(port)
+    if config.HasField('security_params'):
+      creds = implementations.ssl_channel_credentials(
+          resources.test_root_certificates())
+      channel = test_utilities.not_really_secure_channel(
+          host, port, creds, config.security_params.server_host_override)
+    else:
+      channel = implementations.insecure_channel(host, port)
+
+    if config.payload_config.WhichOneof('payload') == 'simple_params':
+      self._generic = False
+      self._stub = services_pb2.beta_create_BenchmarkService_stub(channel)
+      payload = messages_pb2.Payload(
+          body='\0' * config.payload_config.simple_params.req_size)
+      self._request = messages_pb2.SimpleRequest(
+          payload=payload,
+          response_size=config.payload_config.simple_params.resp_size)
+    else:
+      self._generic = True
+      self._stub = implementations.generic_stub(channel)
+      self._request = '\0' * config.payload_config.bytebuf_params.req_size
+
+    self._hist = hist
+    self._response_callbacks = []
+
+  def add_response_callback(self, callback):
+    self._response_callbacks.append(callback)
+
+  @abc.abstractmethod
+  def send_request(self):
+    """Non-blocking wrapper for a client's request operation."""
+    raise NotImplementedError()
+
+  def start(self):
+    pass
+
+  def stop(self):
+    pass
+
+  def _handle_response(self, query_time):
+    self._hist.add(query_time * 1e9)  # Report times in nanoseconds
+    for callback in self._response_callbacks:
+      callback(query_time)
+
+
+class UnarySyncBenchmarkClient(BenchmarkClient):
+
+  def __init__(self, server, config, hist):
+    super(UnarySyncBenchmarkClient, self).__init__(server, config, hist)
+    self._pool = futures.ThreadPoolExecutor(
+        max_workers=config.outstanding_rpcs_per_channel)
+
+  def send_request(self):
+    # Send requests in seperate threads to support multiple outstanding rpcs
+    # (See src/proto/grpc/testing/control.proto)
+    self._pool.submit(self._dispatch_request)
+
+  def stop(self):
+    self._pool.shutdown(wait=True)
+    self._stub = None
+
+  def _dispatch_request(self):
+    start_time = time.time()
+    self._stub.UnaryCall(self._request, _TIMEOUT)
+    end_time = time.time()
+    self._handle_response(end_time - start_time)
+
+
+class UnaryAsyncBenchmarkClient(BenchmarkClient):
+
+  def send_request(self):
+    # Use the Future callback api to support multiple outstanding rpcs
+    start_time = time.time()
+    response_future = self._stub.UnaryCall.future(self._request, _TIMEOUT)
+    response_future.add_done_callback(
+        lambda resp: self._response_received(start_time, resp))
+
+  def _response_received(self, start_time, resp):
+    resp.result()
+    end_time = time.time()
+    self._handle_response(end_time - start_time)
+
+  def stop(self):
+    self._stub = None
+
+
+class StreamingAsyncBenchmarkClient(BenchmarkClient):
+
+  def __init__(self, server, config, hist):
+    super(StreamingAsyncBenchmarkClient, self).__init__(server, config, hist)
+    self._is_streaming = False
+    self._pool = futures.ThreadPoolExecutor(max_workers=1)
+    # Use a thread-safe queue to put requests on the stream
+    self._request_queue = queue.Queue()
+    self._send_time_queue = queue.Queue()
+
+  def send_request(self):
+    self._send_time_queue.put(time.time())
+    self._request_queue.put(self._request)
+
+  def start(self):
+    self._is_streaming = True
+    self._pool.submit(self._request_stream)
+
+  def stop(self):
+    self._is_streaming = False
+    self._pool.shutdown(wait=True)
+    self._stub = None
+
+  def _request_stream(self):
+    self._is_streaming = True
+    if self._generic:
+      response_stream = self._stub.inline_stream_stream(
+          'grpc.testing.BenchmarkService', 'StreamingCall',
+          self._request_generator(), _TIMEOUT)
+    else:
+      response_stream = self._stub.StreamingCall(self._request_generator(),
+                                                 _TIMEOUT)
+    for _ in response_stream:
+      end_time = time.time()
+      self._handle_response(end_time - self._send_time_queue.get_nowait())
+
+  def _request_generator(self):
+    while self._is_streaming:
+      try:
+        request = self._request_queue.get(block=True, timeout=1.0)
+        yield request
+      except queue.Empty:
+        pass
diff --git a/src/python/grpcio/tests/qps/benchmark_server.py b/src/python/grpcio/tests/qps/benchmark_server.py
new file mode 100644
index 0000000..8cbf480
--- /dev/null
+++ b/src/python/grpcio/tests/qps/benchmark_server.py
@@ -0,0 +1,58 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from src.proto.grpc.testing import messages_pb2
+from src.proto.grpc.testing import services_pb2
+
+
+class BenchmarkServer(services_pb2.BetaBenchmarkServiceServicer):
+  """Synchronous Server implementation for the Benchmark service."""
+
+  def UnaryCall(self, request, context):
+    payload = messages_pb2.Payload(body='\0' * request.response_size)
+    return messages_pb2.SimpleResponse(payload=payload)
+
+  def StreamingCall(self, request_iterator, context):
+    for request in request_iterator:
+      payload = messages_pb2.Payload(body='\0' * request.response_size)
+      yield messages_pb2.SimpleResponse(payload=payload)
+
+
+class GenericBenchmarkServer(services_pb2.BetaBenchmarkServiceServicer):
+  """Generic Server implementation for the Benchmark service."""
+
+  def __init__(self, resp_size):
+    self._response = '\0' * resp_size
+
+  def UnaryCall(self, request, context):
+    return self._response
+
+  def StreamingCall(self, request_iterator, context):
+    for request in request_iterator:
+      yield self._response
diff --git a/src/python/grpcio/tests/qps/client_runner.py b/src/python/grpcio/tests/qps/client_runner.py
new file mode 100644
index 0000000..a36c30c
--- /dev/null
+++ b/src/python/grpcio/tests/qps/client_runner.py
@@ -0,0 +1,104 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Defines behavior for WHEN clients send requests.
+
+Each client exposes a non-blocking send_request() method that the
+ClientRunner invokes either periodically or in response to some event.
+"""
+
+import abc
+import thread
+import time
+
+
+class ClientRunner:
+  """Abstract interface for sending requests from clients."""
+
+  __metaclass__ = abc.ABCMeta
+
+  def __init__(self, client):
+    self._client = client
+
+  @abc.abstractmethod
+  def start(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop(self):
+    raise NotImplementedError()
+
+
+class OpenLoopClientRunner(ClientRunner):
+
+  def __init__(self, client, interval_generator):
+    super(OpenLoopClientRunner, self).__init__(client)
+    self._is_running = False
+    self._interval_generator = interval_generator
+
+  def start(self):
+    self._is_running = True
+    self._client.start()
+    thread.start_new_thread(self._dispatch_requests, ())
+
+  def stop(self):
+    self._is_running = False
+    self._client.stop()
+    self._client = None
+
+  def _dispatch_requests(self):
+    while self._is_running:
+      self._client.send_request()
+      time.sleep(next(self._interval_generator))
+
+
+class ClosedLoopClientRunner(ClientRunner):
+
+  def __init__(self, client, request_count):
+    super(ClosedLoopClientRunner, self).__init__(client)
+    self._is_running = False
+    self._request_count = request_count
+    # Send a new request on each response for closed loop
+    self._client.add_response_callback(self._send_request)
+
+  def start(self):
+    self._is_running = True
+    for _ in xrange(self._request_count):
+      self._client.send_request()
+    self._client.start()
+
+  def stop(self):
+    self._is_running = False
+    self._client.stop()
+    self._client = None
+
+  def _send_request(self, response_time):
+    if self._is_running:
+      self._client.send_request()
+
diff --git a/src/python/grpcio/tests/qps/histogram.py b/src/python/grpcio/tests/qps/histogram.py
new file mode 100644
index 0000000..9a7b5eb
--- /dev/null
+++ b/src/python/grpcio/tests/qps/histogram.py
@@ -0,0 +1,85 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import math
+import threading
+
+from src.proto.grpc.testing import stats_pb2
+
+
+class Histogram(object):
+  """Histogram class used for recording performance testing data.
+
+  This class is thread safe.
+  """
+
+  def __init__(self, resolution, max_possible):
+    self._lock = threading.Lock()
+    self._resolution = resolution
+    self._max_possible = max_possible
+    self._sum = 0
+    self._sum_of_squares = 0
+    self.multiplier = 1.0 + self._resolution
+    self._count = 0
+    self._min = self._max_possible
+    self._max = 0
+    self._buckets = [0] * (self._bucket_for(self._max_possible) + 1)
+
+  def reset(self):
+    with self._lock:
+      self._sum = 0
+      self._sum_of_squares = 0
+      self._count = 0
+      self._min = self._max_possible
+      self._max = 0
+      self._buckets = [0] * (self._bucket_for(self._max_possible) + 1)
+
+  def add(self, val):
+    with self._lock:
+      self._sum += val
+      self._sum_of_squares += val * val
+      self._count += 1
+      self._min = min(self._min, val)
+      self._max = max(self._max, val)
+      self._buckets[self._bucket_for(val)] += 1
+
+  def get_data(self):
+    with self._lock:
+      data = stats_pb2.HistogramData()
+      data.bucket.extend(self._buckets)
+      data.min_seen = self._min
+      data.max_seen = self._max
+      data.sum = self._sum
+      data.sum_of_squares = self._sum_of_squares
+      data.count = self._count
+      return data
+
+  def _bucket_for(self, val):
+    val = min(val, self._max_possible)
+    return int(math.log(val, self.multiplier))
diff --git a/tools/dockerfile/grpc_interop_node/build_interop.sh b/src/python/grpcio/tests/qps/qps_worker.py
old mode 100755
new mode 100644
similarity index 63%
copy from tools/dockerfile/grpc_interop_node/build_interop.sh
copy to src/python/grpcio/tests/qps/qps_worker.py
index 4d4290d..3dda718
--- a/tools/dockerfile/grpc_interop_node/build_interop.sh
+++ b/src/python/grpcio/tests/qps/qps_worker.py
@@ -1,5 +1,4 @@
-#!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,22 +26,35 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Builds Node interop server and client in a base image.
-set -e
 
-mkdir -p /var/local/git
-git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
+"""The entry point for the qps worker."""
 
-# copy service account keys if available
-cp -r /var/local/jenkins/service_account $HOME || true
+import argparse
+import time
 
-cd /var/local/git/grpc
-nvm use 0.12
-nvm alias default 0.12  # prevent the need to run 'nvm use' in every shell
+from src.proto.grpc.testing import services_pb2
 
-make install-certs
+from tests.qps import worker_server
 
-# build Node interop client & server
-npm install -g node-gyp
-npm install --unsafe-perm --build-from-source
+
+def run_worker_server(port):
+  servicer = worker_server.WorkerServer()
+  server = services_pb2.beta_create_WorkerService_server(servicer)
+  server.add_insecure_port('[::]:{}'.format(port))
+  server.start()
+  servicer.wait_for_quit()
+  # Drain outstanding requests for clean exit
+  time.sleep(2)
+  server.stop(0)
+
+
+if __name__ == '__main__':
+  parser = argparse.ArgumentParser(
+      description='gRPC Python performance testing worker')
+  parser.add_argument('--driver_port',
+                      type=int,
+                      dest='port',
+                      help='The port the worker should listen on')
+  args = parser.parse_args()
+
+  run_worker_server(args.port)
diff --git a/src/python/grpcio/tests/qps/worker_server.py b/src/python/grpcio/tests/qps/worker_server.py
new file mode 100644
index 0000000..0b3acc1
--- /dev/null
+++ b/src/python/grpcio/tests/qps/worker_server.py
@@ -0,0 +1,184 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import multiprocessing
+import random
+import threading
+import time
+
+from grpc.beta import implementations
+from grpc.framework.interfaces.face import utilities
+from src.proto.grpc.testing import control_pb2
+from src.proto.grpc.testing import services_pb2
+from src.proto.grpc.testing import stats_pb2
+
+from tests.qps import benchmark_client
+from tests.qps import benchmark_server
+from tests.qps import client_runner
+from tests.qps import histogram
+from tests.unit import resources
+
+
+class WorkerServer(services_pb2.BetaWorkerServiceServicer):
+  """Python Worker Server implementation."""
+
+  def __init__(self):
+    self._quit_event = threading.Event()
+
+  def RunServer(self, request_iterator, context):
+    config = next(request_iterator).setup
+    server, port = self._create_server(config)
+    cores = multiprocessing.cpu_count()
+    server.start()
+    start_time = time.time()
+    yield self._get_server_status(start_time, start_time, port, cores)
+
+    for request in request_iterator:
+      end_time = time.time()
+      status = self._get_server_status(start_time, end_time, port, cores)
+      if request.mark.reset:
+        start_time = end_time
+      yield status
+    server.stop(0)
+
+  def _get_server_status(self, start_time, end_time, port, cores):
+    end_time = time.time()
+    elapsed_time = end_time - start_time
+    stats = stats_pb2.ServerStats(time_elapsed=elapsed_time,
+                                  time_user=elapsed_time,
+                                  time_system=elapsed_time)
+    return control_pb2.ServerStatus(stats=stats, port=port, cores=cores)
+
+  def _create_server(self, config):
+    if config.server_type == control_pb2.SYNC_SERVER:
+      servicer = benchmark_server.BenchmarkServer()
+      server = services_pb2.beta_create_BenchmarkService_server(servicer)
+    elif config.server_type == control_pb2.ASYNC_GENERIC_SERVER:
+      resp_size = config.payload_config.bytebuf_params.resp_size
+      servicer = benchmark_server.GenericBenchmarkServer(resp_size)
+      method_implementations = {
+          ('grpc.testing.BenchmarkService', 'StreamingCall'):
+          utilities.stream_stream_inline(servicer.StreamingCall),
+          ('grpc.testing.BenchmarkService', 'UnaryCall'):
+          utilities.unary_unary_inline(servicer.UnaryCall),
+      }
+      server = implementations.server(method_implementations)
+    else:
+      raise Exception('Unsupported server type {}'.format(config.server_type))
+
+    if config.HasField('security_params'):  # Use SSL
+      server_creds = implementations.ssl_server_credentials([(
+          resources.private_key(), resources.certificate_chain())])
+      port = server.add_secure_port('[::]:{}'.format(config.port), server_creds)
+    else:
+      port = server.add_insecure_port('[::]:{}'.format(config.port))
+
+    return (server, port)
+
+  def RunClient(self, request_iterator, context):
+    config = next(request_iterator).setup
+    client_runners = []
+    qps_data = histogram.Histogram(config.histogram_params.resolution,
+                                   config.histogram_params.max_possible)
+    start_time = time.time()
+
+    # Create a client for each channel
+    for i in xrange(config.client_channels):
+      server = config.server_targets[i % len(config.server_targets)]
+      runner = self._create_client_runner(server, config, qps_data)
+      client_runners.append(runner)
+      runner.start()
+
+    end_time = time.time()
+    yield self._get_client_status(start_time, end_time, qps_data)
+
+    # Respond to stat requests
+    for request in request_iterator:
+      end_time = time.time()
+      status = self._get_client_status(start_time, end_time, qps_data)
+      if request.mark.reset:
+        qps_data.reset()
+        start_time = time.time()
+      yield status
+
+    # Cleanup the clients
+    for runner in client_runners:
+      runner.stop()
+
+  def _get_client_status(self, start_time, end_time, qps_data):
+    latencies = qps_data.get_data()
+    end_time = time.time()
+    elapsed_time = end_time - start_time
+    stats = stats_pb2.ClientStats(latencies=latencies,
+                                  time_elapsed=elapsed_time,
+                                  time_user=elapsed_time,
+                                  time_system=elapsed_time)
+    return control_pb2.ClientStatus(stats=stats)
+
+  def _create_client_runner(self, server, config, qps_data):
+    if config.client_type == control_pb2.SYNC_CLIENT:
+      if config.rpc_type == control_pb2.UNARY:
+        client = benchmark_client.UnarySyncBenchmarkClient(
+            server, config, qps_data)
+      else:
+        raise Exception('STREAMING SYNC client not supported')
+    elif config.client_type == control_pb2.ASYNC_CLIENT:
+      if config.rpc_type == control_pb2.UNARY:
+        client = benchmark_client.UnaryAsyncBenchmarkClient(
+            server, config, qps_data)
+      elif config.rpc_type == control_pb2.STREAMING:
+        client = benchmark_client.StreamingAsyncBenchmarkClient(
+            server, config, qps_data)
+    else:
+      raise Exception('Unsupported client type {}'.format(config.client_type))
+
+    # In multi-channel tests, we split the load across all channels
+    load_factor = float(config.client_channels)
+    if config.load_params.WhichOneof('load') == 'closed_loop':
+      runner = client_runner.ClosedLoopClientRunner(
+          client, config.outstanding_rpcs_per_channel)
+    else:  # Open loop Poisson
+      alpha = config.load_params.poisson.offered_load / load_factor
+      def poisson():
+        while True:
+          yield random.expovariate(alpha)
+
+      runner = client_runner.OpenLoopClientRunner(client, poisson())
+
+    return runner
+
+  def CoreCount(self, request, context):
+    return control_pb2.CoreResponse(cores=multiprocessing.cpu_count())
+
+  def QuitWorker(self, request, context):
+    self._quit_event.set()
+    return control_pb2.Void()
+
+  def wait_for_quit(self):
+    self._quit_event.wait()
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/__init__.py b/src/python/grpcio/tests/unit/framework/face/testing/__init__.py
deleted file mode 100644
index 7086519..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/base_util.py b/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
deleted file mode 100644
index 59652b3..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/base_util.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Utilities for creating Base-layer objects for use in Face-layer tests."""
-
-import abc
-
-import six
-
-# interfaces is referenced from specification in this module.
-from grpc.framework.base import util as _base_util
-from grpc.framework.base import implementations
-from grpc.framework.base import in_memory
-from grpc.framework.base import interfaces  # pylint: disable=unused-import
-from grpc.framework.foundation import logging_pool
-
-_POOL_SIZE_LIMIT = 5
-
-_MAXIMUM_TIMEOUT = 90
-
-
-class LinkedPair(six.with_metaclass(abc.ABCMeta)):
-  """A Front and Back that are linked to one another.
-
-  Attributes:
-    front: An interfaces.Front.
-    back: An interfaces.Back.
-  """
-
-  @abc.abstractmethod
-  def shut_down(self):
-    """Shuts down this object and releases its resources."""
-    raise NotImplementedError()
-
-
-class _LinkedPair(LinkedPair):
-
-  def __init__(self, front, back, pools):
-    self.front = front
-    self.back = back
-    self._pools = pools
-
-  def shut_down(self):
-    _base_util.wait_for_idle(self.front)
-    _base_util.wait_for_idle(self.back)
-
-    for pool in self._pools:
-      pool.shutdown(wait=True)
-
-
-def linked_pair(servicer, default_timeout):
-  """Creates a Server and Stub linked together for use."""
-  link_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  front_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  front_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  front_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  back_work_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  back_transmission_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  back_utility_pool = logging_pool.pool(_POOL_SIZE_LIMIT)
-  pools = (
-      link_pool,
-      front_work_pool, front_transmission_pool, front_utility_pool,
-      back_work_pool, back_transmission_pool, back_utility_pool)
-
-  link = in_memory.Link(link_pool)
-  front = implementations.front_link(
-      front_work_pool, front_transmission_pool, front_utility_pool)
-  back = implementations.back_link(
-      servicer, back_work_pool, back_transmission_pool, back_utility_pool,
-      default_timeout, _MAXIMUM_TIMEOUT)
-  front.join_rear_link(link)
-  link.join_fore_link(front)
-  back.join_fore_link(link)
-  link.join_rear_link(back)
-
-  return _LinkedPair(front, back, pools)
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
deleted file mode 100644
index 2ebe1a3..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/blocking_invocation_inline_service_test_case.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""A test to verify an implementation of the Face layer of RPC Framework."""
-
-# unittest is referenced from specification in this module.
-import abc
-import unittest  # pylint: disable=unused-import
-
-import six
-
-from grpc.framework.face import exceptions
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.face.testing import control
-from tests.unit.framework.face.testing import coverage
-from tests.unit.framework.face.testing import digest
-from tests.unit.framework.face.testing import stock_service
-from tests.unit.framework.face.testing import test_case
-
-
-class BlockingInvocationInlineServiceTestCase(
-    six.with_metaclass(abc.ABCMeta,
-    test_case.FaceTestCase, coverage.BlockingCoverage)):
-  """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must also extend unittest.TestCase.
-  """
-
-  def setUp(self):
-    """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self.control = control.PauseFailControl()
-    self.digest = digest.digest(
-        stock_service.STOCK_TEST_SERVICE, self.control, None)
-
-    self.stub, self.memo = self.set_up_implementation(
-        self.digest.name, self.digest.methods,
-        self.digest.inline_method_implementations, None)
-
-  def tearDown(self):
-    """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self.tear_down_implementation(self.memo)
-
-  def testSuccessfulUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        response = self.stub.blocking_value_in_value_out(
-            name, request, test_constants.LONG_TIMEOUT)
-
-        test_messages.verify(request, response, self)
-
-  def testSuccessfulUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        response_iterator = self.stub.inline_value_in_stream_out(
-            name, request, test_constants.LONG_TIMEOUT)
-        responses = list(response_iterator)
-
-        test_messages.verify(request, responses, self)
-
-  def testSuccessfulStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        response = self.stub.blocking_stream_in_value_out(
-            name, iter(requests), test_constants.LONG_TIMEOUT)
-
-        test_messages.verify(requests, response, self)
-
-  def testSuccessfulStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        response_iterator = self.stub.inline_stream_in_stream_out(
-            name, iter(requests), test_constants.LONG_TIMEOUT)
-        responses = list(response_iterator)
-
-        test_messages.verify(requests, responses, self)
-
-  def testSequentialInvocations(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
-
-        first_response = self.stub.blocking_value_in_value_out(
-            name, first_request, test_constants.SHORT_TIMEOUT)
-
-        test_messages.verify(first_request, first_response, self)
-
-        second_response = self.stub.blocking_value_in_value_out(
-            name, second_request, test_constants.SHORT_TIMEOUT)
-
-        test_messages.verify(second_request, second_response, self)
-
-  def testExpiredUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.pause(), self.assertRaises(
-            exceptions.ExpirationError):
-          multi_callable = self.stub.unary_unary_multi_callable(name)
-          multi_callable(request, test_constants.SHORT_TIMEOUT)
-
-  def testExpiredUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.pause(), self.assertRaises(
-            exceptions.ExpirationError):
-          response_iterator = self.stub.inline_value_in_stream_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-          list(response_iterator)
-
-  def testExpiredStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.pause(), self.assertRaises(
-            exceptions.ExpirationError):
-          multi_callable = self.stub.stream_unary_multi_callable(name)
-          multi_callable(iter(requests), test_constants.SHORT_TIMEOUT)
-
-  def testExpiredStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.pause(), self.assertRaises(
-            exceptions.ExpirationError):
-          response_iterator = self.stub.inline_stream_in_stream_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-          list(response_iterator)
-
-  def testFailedUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.fail(), self.assertRaises(exceptions.ServicerError):
-          self.stub.blocking_value_in_value_out(name, request,
-                                                test_constants.SHORT_TIMEOUT)
-
-  def testFailedUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.fail(), self.assertRaises(exceptions.ServicerError):
-          response_iterator = self.stub.inline_value_in_stream_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-          list(response_iterator)
-
-  def testFailedStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.fail(), self.assertRaises(exceptions.ServicerError):
-          self.stub.blocking_stream_in_value_out(name, iter(requests),
-                                                 test_constants.SHORT_TIMEOUT)
-
-  def testFailedStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.fail(), self.assertRaises(exceptions.ServicerError):
-          response_iterator = self.stub.inline_stream_in_stream_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-          list(response_iterator)
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/callback.py b/src/python/grpcio/tests/unit/framework/face/testing/callback.py
deleted file mode 100644
index d0e63c8..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/callback.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""A utility useful in tests of asynchronous, event-driven interfaces."""
-
-import threading
-
-from grpc.framework.foundation import stream
-
-
-class Callback(stream.Consumer):
-  """A utility object useful in tests of asynchronous code."""
-
-  def __init__(self):
-    self._condition = threading.Condition()
-    self._unary_response = None
-    self._streamed_responses = []
-    self._completed = False
-    self._abortion = None
-
-  def abort(self, abortion):
-    with self._condition:
-      self._abortion = abortion
-      self._condition.notify_all()
-
-  def complete(self, unary_response):
-    with self._condition:
-      self._unary_response = unary_response
-      self._completed = True
-      self._condition.notify_all()
-
-  def consume(self, streamed_response):
-    with self._condition:
-      self._streamed_responses.append(streamed_response)
-
-  def terminate(self):
-    with self._condition:
-      self._completed = True
-      self._condition.notify_all()
-
-  def consume_and_terminate(self, streamed_response):
-    with self._condition:
-      self._streamed_responses.append(streamed_response)
-      self._completed = True
-      self._condition.notify_all()
-
-  def block_until_terminated(self):
-    with self._condition:
-      while self._abortion is None and not self._completed:
-        self._condition.wait()
-
-  def response(self):
-    with self._condition:
-      if self._abortion is None:
-        return self._unary_response
-      else:
-        raise AssertionError('Aborted with abortion "%s"!' % self._abortion)
-
-  def responses(self):
-    with self._condition:
-      if self._abortion is None:
-        return list(self._streamed_responses)
-      else:
-        raise AssertionError('Aborted with abortion "%s"!' % self._abortion)
-
-  def abortion(self):
-    with self._condition:
-      return self._abortion
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/control.py b/src/python/grpcio/tests/unit/framework/face/testing/control.py
deleted file mode 100644
index 8425aff..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/control.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Code for instructing systems under test to block or fail."""
-
-import abc
-import contextlib
-import threading
-
-import six
-
-
-class Control(six.with_metaclass(abc.ABCMeta)):
-  """An object that accepts program control from a system under test.
-
-  Systems under test passed a Control should call its control() method
-  frequently during execution. The control() method may block, raise an
-  exception, or do nothing, all according to the enclosing test's desire for
-  the system under test to simulate hanging, failing, or functioning.
-  """
-
-  @abc.abstractmethod
-  def control(self):
-    """Potentially does anything."""
-    raise NotImplementedError()
-
-
-class PauseFailControl(Control):
-  """A Control that can be used to pause or fail code under control."""
-
-  def __init__(self):
-    self._condition = threading.Condition()
-    self._paused = False
-    self._fail = False
-
-  def control(self):
-    with self._condition:
-      if self._fail:
-        raise ValueError()
-
-      while self._paused:
-        self._condition.wait()
-
-  @contextlib.contextmanager
-  def pause(self):
-    """Pauses code under control while controlling code is in context."""
-    with self._condition:
-      self._paused = True
-    yield
-    with self._condition:
-      self._paused = False
-      self._condition.notify_all()
-
-  @contextlib.contextmanager
-  def fail(self):
-    """Fails code under control while controlling code is in context."""
-    with self._condition:
-      self._fail = True
-    yield
-    with self._condition:
-      self._fail = False
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/coverage.py b/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
deleted file mode 100644
index 3c88b78..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/coverage.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Governs coverage for the tests of the Face layer of RPC Framework."""
-
-import abc
-
-import six
-
-# These classes are only valid when inherited by unittest.TestCases.
-# pylint: disable=invalid-name
-
-
-class BlockingCoverage(six.with_metaclass(abc.ABCMeta)):
-  """Specification of test coverage for blocking behaviors."""
-
-  @abc.abstractmethod
-  def testSuccessfulUnaryRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testSuccessfulUnaryRequestStreamResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testSuccessfulStreamRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testSuccessfulStreamRequestStreamResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testSequentialInvocations(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testExpiredUnaryRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testExpiredUnaryRequestStreamResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testExpiredStreamRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testExpiredStreamRequestStreamResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testFailedUnaryRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testFailedUnaryRequestStreamResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testFailedStreamRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testFailedStreamRequestStreamResponse(self):
-    raise NotImplementedError()
-
-
-class FullCoverage(six.with_metaclass(abc.ABCMeta, BlockingCoverage)):
-  """Specification of test coverage for non-blocking behaviors."""
-
-  @abc.abstractmethod
-  def testParallelInvocations(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testCancelledUnaryRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testCancelledUnaryRequestStreamResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testCancelledStreamRequestUnaryResponse(self):
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def testCancelledStreamRequestStreamResponse(self):
-    raise NotImplementedError()
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/digest.py b/src/python/grpcio/tests/unit/framework/face/testing/digest.py
deleted file mode 100644
index 2b45ade..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/digest.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Code for making a service.TestService more amenable to use in tests."""
-
-import collections
-import threading
-
-import six
-
-# testing_control, interfaces, and testing_service are referenced from
-# specification in this module.
-from grpc.framework.common import cardinality
-from grpc.framework.common import style
-from grpc.framework.face import exceptions
-from grpc.framework.face import interfaces as face_interfaces
-from grpc.framework.foundation import stream
-from grpc.framework.foundation import stream_util
-from tests.unit.framework.face.testing import control as testing_control  # pylint: disable=unused-import
-from tests.unit.framework.face.testing import interfaces  # pylint: disable=unused-import
-from tests.unit.framework.face.testing import service as testing_service  # pylint: disable=unused-import
-
-_IDENTITY = lambda x: x
-
-
-class TestServiceDigest(
-    collections.namedtuple(
-        'TestServiceDigest',
-        ['name',
-         'methods',
-         'inline_method_implementations',
-         'event_method_implementations',
-         'multi_method_implementation',
-         'unary_unary_messages_sequences',
-         'unary_stream_messages_sequences',
-         'stream_unary_messages_sequences',
-         'stream_stream_messages_sequences'])):
-  """A transformation of a service.TestService.
-
-  Attributes:
-    name: The RPC service name to be used in the test.
-    methods: A sequence of interfaces.Method objects describing the RPC
-      methods that will be called during the test.
-    inline_method_implementations: A dict from RPC method name to
-      face_interfaces.MethodImplementation object to be used in tests of
-      in-line calls to behaviors under test.
-    event_method_implementations: A dict from RPC method name to
-      face_interfaces.MethodImplementation object to be used in tests of
-      event-driven calls to behaviors under test.
-    multi_method_implementation: A face_interfaces.MultiMethodImplementation to
-      be used in tests of generic calls to behaviors under test.
-    unary_unary_messages_sequences: A dict from method name to sequence of
-      service.UnaryUnaryTestMessages objects to be used to test the method
-      with the given name.
-    unary_stream_messages_sequences: A dict from method name to sequence of
-      service.UnaryStreamTestMessages objects to be used to test the method
-      with the given name.
-    stream_unary_messages_sequences: A dict from method name to sequence of
-      service.StreamUnaryTestMessages objects to be used to test the method
-      with the given name.
-    stream_stream_messages_sequences: A dict from method name to sequence of
-      service.StreamStreamTestMessages objects to be used to test the
-      method with the given name.
-    serialization: A serial.Serialization object describing serialization
-      behaviors for all the RPC methods.
-  """
-
-
-class _BufferingConsumer(stream.Consumer):
-  """A trivial Consumer that dumps what it consumes in a user-mutable buffer."""
-
-  def __init__(self):
-    self.consumed = []
-    self.terminated = False
-
-  def consume(self, value):
-    self.consumed.append(value)
-
-  def terminate(self):
-    self.terminated = True
-
-  def consume_and_terminate(self, value):
-    self.consumed.append(value)
-    self.terminated = True
-
-
-class _InlineUnaryUnaryMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, unary_unary_test_method, control):
-    self._test_method = unary_unary_test_method
-    self._control = control
-
-    self.cardinality = cardinality.Cardinality.UNARY_UNARY
-    self.style = style.Service.INLINE
-
-  def unary_unary_inline(self, request, context):
-    response_list = []
-    self._test_method.service(
-        request, response_list.append, context, self._control)
-    return response_list.pop(0)
-
-
-class _EventUnaryUnaryMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, unary_unary_test_method, control, pool):
-    self._test_method = unary_unary_test_method
-    self._control = control
-    self._pool = pool
-
-    self.cardinality = cardinality.Cardinality.UNARY_UNARY
-    self.style = style.Service.EVENT
-
-  def unary_unary_event(self, request, response_callback, context):
-    if self._pool is None:
-      self._test_method.service(
-          request, response_callback, context, self._control)
-    else:
-      self._pool.submit(
-          self._test_method.service, request, response_callback, context,
-          self._control)
-
-
-class _InlineUnaryStreamMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, unary_stream_test_method, control):
-    self._test_method = unary_stream_test_method
-    self._control = control
-
-    self.cardinality = cardinality.Cardinality.UNARY_STREAM
-    self.style = style.Service.INLINE
-
-  def unary_stream_inline(self, request, context):
-    response_consumer = _BufferingConsumer()
-    self._test_method.service(
-        request, response_consumer, context, self._control)
-    for response in response_consumer.consumed:
-      yield response
-
-
-class _EventUnaryStreamMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, unary_stream_test_method, control, pool):
-    self._test_method = unary_stream_test_method
-    self._control = control
-    self._pool = pool
-
-    self.cardinality = cardinality.Cardinality.UNARY_STREAM
-    self.style = style.Service.EVENT
-
-  def unary_stream_event(self, request, response_consumer, context):
-    if self._pool is None:
-      self._test_method.service(
-          request, response_consumer, context, self._control)
-    else:
-      self._pool.submit(
-          self._test_method.service, request, response_consumer, context,
-          self._control)
-
-
-class _InlineStreamUnaryMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, stream_unary_test_method, control):
-    self._test_method = stream_unary_test_method
-    self._control = control
-
-    self.cardinality = cardinality.Cardinality.STREAM_UNARY
-    self.style = style.Service.INLINE
-
-  def stream_unary_inline(self, request_iterator, context):
-    response_list = []
-    request_consumer = self._test_method.service(
-        response_list.append, context, self._control)
-    for request in request_iterator:
-      request_consumer.consume(request)
-    request_consumer.terminate()
-    return response_list.pop(0)
-
-
-class _EventStreamUnaryMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, stream_unary_test_method, control, pool):
-    self._test_method = stream_unary_test_method
-    self._control = control
-    self._pool = pool
-
-    self.cardinality = cardinality.Cardinality.STREAM_UNARY
-    self.style = style.Service.EVENT
-
-  def stream_unary_event(self, response_callback, context):
-    request_consumer = self._test_method.service(
-        response_callback, context, self._control)
-    if self._pool is None:
-      return request_consumer
-    else:
-      return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
-
-
-class _InlineStreamStreamMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, stream_stream_test_method, control):
-    self._test_method = stream_stream_test_method
-    self._control = control
-
-    self.cardinality = cardinality.Cardinality.STREAM_STREAM
-    self.style = style.Service.INLINE
-
-  def stream_stream_inline(self, request_iterator, context):
-    response_consumer = _BufferingConsumer()
-    request_consumer = self._test_method.service(
-        response_consumer, context, self._control)
-
-    for request in request_iterator:
-      request_consumer.consume(request)
-      while response_consumer.consumed:
-        yield response_consumer.consumed.pop(0)
-    response_consumer.terminate()
-
-
-class _EventStreamStreamMethod(face_interfaces.MethodImplementation):
-
-  def __init__(self, stream_stream_test_method, control, pool):
-    self._test_method = stream_stream_test_method
-    self._control = control
-    self._pool = pool
-
-    self.cardinality = cardinality.Cardinality.STREAM_STREAM
-    self.style = style.Service.EVENT
-
-  def stream_stream_event(self, response_consumer, context):
-    request_consumer = self._test_method.service(
-        response_consumer, context, self._control)
-    if self._pool is None:
-      return request_consumer
-    else:
-      return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
-
-
-class _UnaryConsumer(stream.Consumer):
-  """A Consumer that only allows consumption of exactly one value."""
-
-  def __init__(self, action):
-    self._lock = threading.Lock()
-    self._action = action
-    self._consumed = False
-    self._terminated = False
-
-  def consume(self, value):
-    with self._lock:
-      if self._consumed:
-        raise ValueError('Unary consumer already consumed!')
-      elif self._terminated:
-        raise ValueError('Unary consumer already terminated!')
-      else:
-        self._consumed = True
-
-    self._action(value)
-
-  def terminate(self):
-    with self._lock:
-      if not self._consumed:
-        raise ValueError('Unary consumer hasn\'t yet consumed!')
-      elif self._terminated:
-        raise ValueError('Unary consumer already terminated!')
-      else:
-        self._terminated = True
-
-  def consume_and_terminate(self, value):
-    with self._lock:
-      if self._consumed:
-        raise ValueError('Unary consumer already consumed!')
-      elif self._terminated:
-        raise ValueError('Unary consumer already terminated!')
-      else:
-        self._consumed = True
-        self._terminated = True
-
-    self._action(value)
-
-
-class _UnaryUnaryAdaptation(object):
-
-  def __init__(self, unary_unary_test_method):
-    self._method = unary_unary_test_method
-
-  def service(self, response_consumer, context, control):
-    def action(request):
-      self._method.service(
-          request, response_consumer.consume_and_terminate, context, control)
-    return _UnaryConsumer(action)
-
-
-class _UnaryStreamAdaptation(object):
-
-  def __init__(self, unary_stream_test_method):
-    self._method = unary_stream_test_method
-
-  def service(self, response_consumer, context, control):
-    def action(request):
-      self._method.service(request, response_consumer, context, control)
-    return _UnaryConsumer(action)
-
-
-class _StreamUnaryAdaptation(object):
-
-  def __init__(self, stream_unary_test_method):
-    self._method = stream_unary_test_method
-
-  def service(self, response_consumer, context, control):
-    return self._method.service(
-        response_consumer.consume_and_terminate, context, control)
-
-
-class _MultiMethodImplementation(face_interfaces.MultiMethodImplementation):
-
-  def __init__(self, methods, control, pool):
-    self._methods = methods
-    self._control = control
-    self._pool = pool
-
-  def service(self, name, response_consumer, context):
-    method = self._methods.get(name, None)
-    if method is None:
-      raise exceptions.NoSuchMethodError(name)
-    elif self._pool is None:
-      return method(response_consumer, context, self._control)
-    else:
-      request_consumer = method(response_consumer, context, self._control)
-      return stream_util.ThreadSwitchingConsumer(request_consumer, self._pool)
-
-
-class _Assembly(
-    collections.namedtuple(
-        '_Assembly',
-        ['methods', 'inlines', 'events', 'adaptations', 'messages'])):
-  """An intermediate structure created when creating a TestServiceDigest."""
-
-
-def _assemble(
-    scenarios, names, inline_method_constructor, event_method_constructor,
-    adapter, control, pool):
-  """Creates an _Assembly from the given scenarios."""
-  methods = []
-  inlines = {}
-  events = {}
-  adaptations = {}
-  messages = {}
-  for name, scenario in six.iteritems(scenarios):
-    if name in names:
-      raise ValueError('Repeated name "%s"!' % name)
-
-    test_method = scenario[0]
-    inline_method = inline_method_constructor(test_method, control)
-    event_method = event_method_constructor(test_method, control, pool)
-    adaptation = adapter(test_method)
-
-    methods.append(test_method)
-    inlines[name] = inline_method
-    events[name] = event_method
-    adaptations[name] = adaptation
-    messages[name] = scenario[1]
-
-  return _Assembly(methods, inlines, events, adaptations, messages)
-
-
-def digest(service, control, pool):
-  """Creates a TestServiceDigest from a TestService.
-
-  Args:
-    service: A testing_service.TestService.
-    control: A testing_control.Control.
-    pool: If RPC methods should be serviced in a separate thread, a thread pool.
-      None if RPC methods should be serviced in the thread belonging to the
-      run-time that calls for their service.
-
-  Returns:
-    A TestServiceDigest synthesized from the given service.TestService.
-  """
-  names = set()
-
-  unary_unary = _assemble(
-      service.unary_unary_scenarios(), names, _InlineUnaryUnaryMethod,
-      _EventUnaryUnaryMethod, _UnaryUnaryAdaptation, control, pool)
-  names.update(set(unary_unary.inlines))
-
-  unary_stream = _assemble(
-      service.unary_stream_scenarios(), names, _InlineUnaryStreamMethod,
-      _EventUnaryStreamMethod, _UnaryStreamAdaptation, control, pool)
-  names.update(set(unary_stream.inlines))
-
-  stream_unary = _assemble(
-      service.stream_unary_scenarios(), names, _InlineStreamUnaryMethod,
-      _EventStreamUnaryMethod, _StreamUnaryAdaptation, control, pool)
-  names.update(set(stream_unary.inlines))
-
-  stream_stream = _assemble(
-      service.stream_stream_scenarios(), names, _InlineStreamStreamMethod,
-      _EventStreamStreamMethod, _IDENTITY, control, pool)
-  names.update(set(stream_stream.inlines))
-
-  methods = list(unary_unary.methods)
-  methods.extend(unary_stream.methods)
-  methods.extend(stream_unary.methods)
-  methods.extend(stream_stream.methods)
-  adaptations = dict(unary_unary.adaptations)
-  adaptations.update(unary_stream.adaptations)
-  adaptations.update(stream_unary.adaptations)
-  adaptations.update(stream_stream.adaptations)
-  inlines = dict(unary_unary.inlines)
-  inlines.update(unary_stream.inlines)
-  inlines.update(stream_unary.inlines)
-  inlines.update(stream_stream.inlines)
-  events = dict(unary_unary.events)
-  events.update(unary_stream.events)
-  events.update(stream_unary.events)
-  events.update(stream_stream.events)
-
-  return TestServiceDigest(
-      service.name(),
-      methods,
-      inlines,
-      events,
-      _MultiMethodImplementation(adaptations, control, pool),
-      unary_unary.messages,
-      unary_stream.messages,
-      stream_unary.messages,
-      stream_stream.messages)
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
deleted file mode 100644
index 98b61e4..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/event_invocation_synchronous_event_service_test_case.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""A test to verify an implementation of the Face layer of RPC Framework."""
-
-import abc
-import unittest
-
-import six
-
-from grpc.framework.face import interfaces
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.face.testing import callback as testing_callback
-from tests.unit.framework.face.testing import control
-from tests.unit.framework.face.testing import coverage
-from tests.unit.framework.face.testing import digest
-from tests.unit.framework.face.testing import stock_service
-from tests.unit.framework.face.testing import test_case
-
-
-class EventInvocationSynchronousEventServiceTestCase(
-    six.with_metaclass(abc.ABCMeta,
-    test_case.FaceTestCase, coverage.FullCoverage)):
-  """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must also extend unittest.TestCase.
-  """
-
-  def setUp(self):
-    """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self.control = control.PauseFailControl()
-    self.digest = digest.digest(
-        stock_service.STOCK_TEST_SERVICE, self.control, None)
-
-    self.stub, self.memo = self.set_up_implementation(
-        self.digest.name, self.digest.methods,
-        self.digest.event_method_implementations, None)
-
-  def tearDown(self):
-    """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self.tear_down_implementation(self.memo)
-
-  def testSuccessfulUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        self.stub.event_value_in_value_out(
-            name, request, callback.complete, callback.abort,
-            test_constants.SHORT_TIMEOUT)
-        callback.block_until_terminated()
-        response = callback.response()
-
-        test_messages.verify(request, response, self)
-
-  def testSuccessfulUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        self.stub.event_value_in_stream_out(
-            name, request, callback, callback.abort,
-            test_constants.SHORT_TIMEOUT)
-        callback.block_until_terminated()
-        responses = callback.responses()
-
-        test_messages.verify(request, responses, self)
-
-  def testSuccessfulStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        callback = testing_callback.Callback()
-
-        unused_call, request_consumer = self.stub.event_stream_in_value_out(
-            name, callback.complete, callback.abort,
-            test_constants.SHORT_TIMEOUT)
-        for request in requests:
-          request_consumer.consume(request)
-        request_consumer.terminate()
-        callback.block_until_terminated()
-        response = callback.response()
-
-        test_messages.verify(requests, response, self)
-
-  def testSuccessfulStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        callback = testing_callback.Callback()
-
-        unused_call, request_consumer = self.stub.event_stream_in_stream_out(
-            name, callback, callback.abort, test_constants.SHORT_TIMEOUT)
-        for request in requests:
-          request_consumer.consume(request)
-        request_consumer.terminate()
-        callback.block_until_terminated()
-        responses = callback.responses()
-
-        test_messages.verify(requests, responses, self)
-
-  def testSequentialInvocations(self):
-    # pylint: disable=cell-var-from-loop
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
-        first_callback = testing_callback.Callback()
-        second_callback = testing_callback.Callback()
-
-        def make_second_invocation(first_response):
-          first_callback.complete(first_response)
-          self.stub.event_value_in_value_out(
-              name, second_request, second_callback.complete,
-              second_callback.abort, test_constants.SHORT_TIMEOUT)
-
-        self.stub.event_value_in_value_out(
-            name, first_request, make_second_invocation, first_callback.abort,
-           test_constants.SHORT_TIMEOUT)
-        second_callback.block_until_terminated()
-
-        first_response = first_callback.response()
-        second_response = second_callback.response()
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  def testExpiredUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        with self.control.pause():
-          self.stub.event_value_in_value_out(
-              name, request, callback.complete, callback.abort,
-              test_constants.SHORT_TIMEOUT)
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
-
-  def testExpiredUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        with self.control.pause():
-          self.stub.event_value_in_stream_out(
-              name, request, callback, callback.abort,
-              test_constants.SHORT_TIMEOUT)
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
-
-  def testExpiredStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for unused_test_messages in test_messages_sequence:
-        callback = testing_callback.Callback()
-
-        self.stub.event_stream_in_value_out(
-            name, callback.complete, callback.abort,
-            test_constants.SHORT_TIMEOUT)
-        callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
-
-  def testExpiredStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        callback = testing_callback.Callback()
-
-        unused_call, request_consumer = self.stub.event_stream_in_stream_out(
-            name, callback, callback.abort, test_constants.SHORT_TIMEOUT)
-        for request in requests:
-          request_consumer.consume(request)
-        callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.EXPIRED, callback.abortion())
-
-  def testFailedUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        with self.control.fail():
-          self.stub.event_value_in_value_out(
-              name, request, callback.complete, callback.abort,
-              test_constants.SHORT_TIMEOUT)
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.SERVICER_FAILURE,
-                         callback.abortion())
-
-  def testFailedUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        with self.control.fail():
-          self.stub.event_value_in_stream_out(
-              name, request, callback, callback.abort,
-              test_constants.SHORT_TIMEOUT)
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.SERVICER_FAILURE,
-                         callback.abortion())
-
-  def testFailedStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        callback = testing_callback.Callback()
-
-        with self.control.fail():
-          unused_call, request_consumer = self.stub.event_stream_in_value_out(
-              name, callback.complete, callback.abort,
-              test_constants.SHORT_TIMEOUT)
-          for request in requests:
-            request_consumer.consume(request)
-          request_consumer.terminate()
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.SERVICER_FAILURE,
-                         callback.abortion())
-
-  def testFailedStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        callback = testing_callback.Callback()
-
-        with self.control.fail():
-          unused_call, request_consumer = self.stub.event_stream_in_stream_out(
-              name, callback, callback.abort, test_constants.SHORT_TIMEOUT)
-          for request in requests:
-            request_consumer.consume(request)
-          request_consumer.terminate()
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.SERVICER_FAILURE, callback.abortion())
-
-  def testParallelInvocations(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        first_callback = testing_callback.Callback()
-        second_request = test_messages.request()
-        second_callback = testing_callback.Callback()
-
-        self.stub.event_value_in_value_out(
-            name, first_request, first_callback.complete, first_callback.abort,
-           test_constants.SHORT_TIMEOUT)
-        self.stub.event_value_in_value_out(
-            name, second_request, second_callback.complete,
-            second_callback.abort, test_constants.SHORT_TIMEOUT)
-        first_callback.block_until_terminated()
-        second_callback.block_until_terminated()
-
-        first_response = first_callback.response()
-        second_response = second_callback.response()
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  @unittest.skip('TODO(nathaniel): implement.')
-  def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
-
-  def testCancelledUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        with self.control.pause():
-          call = self.stub.event_value_in_value_out(
-              name, request, callback.complete, callback.abort,
-              test_constants.SHORT_TIMEOUT)
-          call.cancel()
-          callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
-
-  def testCancelledUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        callback = testing_callback.Callback()
-
-        call = self.stub.event_value_in_stream_out(
-            name, request, callback, callback.abort,
-            test_constants.SHORT_TIMEOUT)
-        call.cancel()
-        callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
-
-  def testCancelledStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        callback = testing_callback.Callback()
-
-        call, request_consumer = self.stub.event_stream_in_value_out(
-            name, callback.complete, callback.abort,
-            test_constants.SHORT_TIMEOUT)
-        for request in requests:
-          request_consumer.consume(request)
-        call.cancel()
-        callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
-
-  def testCancelledStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for unused_test_messages in test_messages_sequence:
-        callback = testing_callback.Callback()
-
-        call, unused_request_consumer = self.stub.event_stream_in_stream_out(
-            name, callback, callback.abort, test_constants.SHORT_TIMEOUT)
-        call.cancel()
-        callback.block_until_terminated()
-
-        self.assertEqual(interfaces.Abortion.CANCELLED, callback.abortion())
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
deleted file mode 100644
index cae791a..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/future_invocation_asynchronous_event_service_test_case.py
+++ /dev/null
@@ -1,384 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""A test to verify an implementation of the Face layer of RPC Framework."""
-
-import abc
-import contextlib
-import threading
-import unittest
-
-import six
-
-from grpc.framework.face import exceptions
-from grpc.framework.foundation import future
-from grpc.framework.foundation import logging_pool
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.face.testing import control
-from tests.unit.framework.face.testing import coverage
-from tests.unit.framework.face.testing import digest
-from tests.unit.framework.face.testing import stock_service
-from tests.unit.framework.face.testing import test_case
-
-_MAXIMUM_POOL_SIZE = 10
-
-
-class _PauseableIterator(object):
-
-  def __init__(self, upstream):
-    self._upstream = upstream
-    self._condition = threading.Condition()
-    self._paused = False
-
-  @contextlib.contextmanager
-  def pause(self):
-    with self._condition:
-      self._paused = True
-    yield
-    with self._condition:
-      self._paused = False
-      self._condition.notify_all()
-
-  def __iter__(self):
-    return self
-
-  def __next__(self):
-    return self.next()
-
-  def next(self):
-    with self._condition:
-      while self._paused:
-        self._condition.wait()
-    return next(self._upstream)
-
-
-class FutureInvocationAsynchronousEventServiceTestCase(
-    six.with_metaclass(abc.ABCMeta,
-    test_case.FaceTestCase, coverage.FullCoverage)):
-  """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must also extend unittest.TestCase.
-  """
-
-  def setUp(self):
-    """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self.control = control.PauseFailControl()
-    self.digest_pool = logging_pool.pool(_MAXIMUM_POOL_SIZE)
-    self.digest = digest.digest(
-        stock_service.STOCK_TEST_SERVICE, self.control, self.digest_pool)
-
-    self.stub, self.memo = self.set_up_implementation(
-        self.digest.name, self.digest.methods,
-        self.digest.event_method_implementations, None)
-
-  def tearDown(self):
-    """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self.tear_down_implementation(self.memo)
-    self.digest_pool.shutdown(wait=True)
-
-  def testSuccessfulUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        response_future = self.stub.future_value_in_value_out(
-            name, request, test_constants.SHORT_TIMEOUT)
-        response = response_future.result()
-
-        test_messages.verify(request, response, self)
-
-  def testSuccessfulUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        response_iterator = self.stub.inline_value_in_stream_out(
-            name, request, test_constants.SHORT_TIMEOUT)
-        responses = list(response_iterator)
-
-        test_messages.verify(request, responses, self)
-
-  def testSuccessfulStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        request_iterator = _PauseableIterator(iter(requests))
-
-        # Use of a paused iterator of requests allows us to test that control is
-        # returned to calling code before the iterator yields any requests.
-        with request_iterator.pause():
-          response_future = self.stub.future_stream_in_value_out(
-              name, request_iterator, test_constants.SHORT_TIMEOUT)
-        response = response_future.result()
-
-        test_messages.verify(requests, response, self)
-
-  def testSuccessfulStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        request_iterator = _PauseableIterator(iter(requests))
-
-        # Use of a paused iterator of requests allows us to test that control is
-        # returned to calling code before the iterator yields any requests.
-        with request_iterator.pause():
-          response_iterator = self.stub.inline_stream_in_stream_out(
-              name, request_iterator, test_constants.SHORT_TIMEOUT)
-        responses = list(response_iterator)
-
-        test_messages.verify(requests, responses, self)
-
-  def testSequentialInvocations(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
-
-        first_response_future = self.stub.future_value_in_value_out(
-            name, first_request, test_constants.SHORT_TIMEOUT)
-        first_response = first_response_future.result()
-
-        test_messages.verify(first_request, first_response, self)
-
-        second_response_future = self.stub.future_value_in_value_out(
-            name, second_request, test_constants.SHORT_TIMEOUT)
-        second_response = second_response_future.result()
-
-        test_messages.verify(second_request, second_response, self)
-
-  def testExpiredUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.pause():
-          multi_callable = self.stub.unary_unary_multi_callable(name)
-          response_future = multi_callable.future(request,
-                                                  test_constants.SHORT_TIMEOUT)
-          self.assertIsInstance(
-              response_future.exception(), exceptions.ExpirationError)
-          with self.assertRaises(exceptions.ExpirationError):
-            response_future.result()
-
-  def testExpiredUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.pause():
-          response_iterator = self.stub.inline_value_in_stream_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-          with self.assertRaises(exceptions.ExpirationError):
-            list(response_iterator)
-
-  def testExpiredStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.pause():
-          multi_callable = self.stub.stream_unary_multi_callable(name)
-          response_future = multi_callable.future(iter(requests),
-                                                  test_constants.SHORT_TIMEOUT)
-          self.assertIsInstance(
-              response_future.exception(), exceptions.ExpirationError)
-          with self.assertRaises(exceptions.ExpirationError):
-            response_future.result()
-
-  def testExpiredStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.pause():
-          response_iterator = self.stub.inline_stream_in_stream_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-          with self.assertRaises(exceptions.ExpirationError):
-            list(response_iterator)
-
-  def testFailedUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.fail():
-          response_future = self.stub.future_value_in_value_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-
-          # Because the servicer fails outside of the thread from which the
-          # servicer-side runtime called into it its failure is
-          # indistinguishable from simply not having called its
-          # response_callback before the expiration of the RPC.
-          self.assertIsInstance(
-              response_future.exception(), exceptions.ExpirationError)
-          with self.assertRaises(exceptions.ExpirationError):
-            response_future.result()
-
-  def testFailedUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        # Because the servicer fails outside of the thread from which the
-        # servicer-side runtime called into it its failure is indistinguishable
-        # from simply not having called its response_consumer before the
-        # expiration of the RPC.
-        with self.control.fail(), self.assertRaises(exceptions.ExpirationError):
-          response_iterator = self.stub.inline_value_in_stream_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-          list(response_iterator)
-
-  def testFailedStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.fail():
-          response_future = self.stub.future_stream_in_value_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-
-          # Because the servicer fails outside of the thread from which the
-          # servicer-side runtime called into it its failure is
-          # indistinguishable from simply not having called its
-          # response_callback before the expiration of the RPC.
-          self.assertIsInstance(
-              response_future.exception(), exceptions.ExpirationError)
-          with self.assertRaises(exceptions.ExpirationError):
-            response_future.result()
-
-  def testFailedStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        # Because the servicer fails outside of the thread from which the
-        # servicer-side runtime called into it its failure is indistinguishable
-        # from simply not having called its response_consumer before the
-        # expiration of the RPC.
-        with self.control.fail(), self.assertRaises(exceptions.ExpirationError):
-          response_iterator = self.stub.inline_stream_in_stream_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-          list(response_iterator)
-
-  def testParallelInvocations(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
-
-        # TODO(bug 2039): use LONG_TIMEOUT instead
-        first_response_future = self.stub.future_value_in_value_out(
-            name, first_request, test_constants.SHORT_TIMEOUT)
-        second_response_future = self.stub.future_value_in_value_out(
-            name, second_request, test_constants.SHORT_TIMEOUT)
-        first_response = first_response_future.result()
-        second_response = second_response_future.result()
-
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  @unittest.skip('TODO(nathaniel): implement.')
-  def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
-
-  def testCancelledUnaryRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.pause():
-          response_future = self.stub.future_value_in_value_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-          cancel_method_return_value = response_future.cancel()
-
-        self.assertFalse(cancel_method_return_value)
-        self.assertTrue(response_future.cancelled())
-
-  def testCancelledUnaryRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.unary_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-
-        with self.control.pause():
-          response_iterator = self.stub.inline_value_in_stream_out(
-              name, request, test_constants.SHORT_TIMEOUT)
-          response_iterator.cancel()
-
-        with self.assertRaises(future.CancelledError):
-          next(response_iterator)
-
-  def testCancelledStreamRequestUnaryResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_unary_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.pause():
-          response_future = self.stub.future_stream_in_value_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-          cancel_method_return_value = response_future.cancel()
-
-        self.assertFalse(cancel_method_return_value)
-        self.assertTrue(response_future.cancelled())
-
-  def testCancelledStreamRequestStreamResponse(self):
-    for name, test_messages_sequence in (
-        six.iteritems(self.digest.stream_stream_messages_sequences)):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-
-        with self.control.pause():
-          response_iterator = self.stub.inline_stream_in_stream_out(
-              name, iter(requests), test_constants.SHORT_TIMEOUT)
-          response_iterator.cancel()
-
-        with self.assertRaises(future.CancelledError):
-          next(response_iterator)
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py b/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
deleted file mode 100644
index 8a25f89..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/interfaces.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Interfaces implemented by data sets used in Face-layer tests."""
-
-import abc
-
-import six
-
-# cardinality is referenced from specification in this module.
-from grpc.framework.common import cardinality  # pylint: disable=unused-import
-
-
-class Method(six.with_metaclass(abc.ABCMeta)):
-  """An RPC method to be used in tests of RPC implementations."""
-
-  @abc.abstractmethod
-  def name(self):
-    """Identify the name of the method.
-
-    Returns:
-      The name of the method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def cardinality(self):
-    """Identify the cardinality of the method.
-
-    Returns:
-      A cardinality.Cardinality value describing the streaming semantics of the
-        method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def request_class(self):
-    """Identify the class used for the method's request objects.
-
-    Returns:
-      The class object of the class to which the method's request objects
-        belong.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def response_class(self):
-    """Identify the class used for the method's response objects.
-
-    Returns:
-      The class object of the class to which the method's response objects
-        belong.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def serialize_request(self, request):
-    """Serialize the given request object.
-
-    Args:
-      request: A request object appropriate for this method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def deserialize_request(self, serialized_request):
-    """Synthesize a request object from a given bytestring.
-
-    Args:
-      serialized_request: A bytestring deserializable into a request object
-        appropriate for this method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def serialize_response(self, response):
-    """Serialize the given response object.
-
-    Args:
-      response: A response object appropriate for this method.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def deserialize_response(self, serialized_response):
-    """Synthesize a response object from a given bytestring.
-
-    Args:
-      serialized_response: A bytestring deserializable into a response object
-        appropriate for this method.
-    """
-    raise NotImplementedError()
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/service.py b/src/python/grpcio/tests/unit/framework/face/testing/service.py
deleted file mode 100644
index 3e4228c..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/service.py
+++ /dev/null
@@ -1,321 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Private interfaces implemented by data sets used in Face-layer tests."""
-
-import abc
-
-import six
-
-# interfaces is referenced from specification in this module.
-from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
-from tests.unit.framework.face.testing import interfaces
-
-
-class UnaryUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
-  """A controllable implementation of a unary-unary RPC method."""
-
-  @abc.abstractmethod
-  def service(self, request, response_callback, context, control):
-    """Services an RPC that accepts one message and produces one message.
-
-    Args:
-      request: The single request message for the RPC.
-      response_callback: A callback to be called to accept the response message
-        of the RPC.
-      context: An face_interfaces.RpcContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-    raise NotImplementedError()
-
-
-class UnaryUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
-  """A type for unary-request-unary-response message pairings."""
-
-  @abc.abstractmethod
-  def request(self):
-    """Affords a request message.
-
-    Implementations of this method should return a different message with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A request message.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def verify(self, request, response, test_case):
-    """Verifies that the computed response matches the given request.
-
-    Args:
-      request: A request message.
-      response: A response message.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the request and response do not match, indicating that
-        there was some problem executing the RPC under test.
-    """
-    raise NotImplementedError()
-
-
-class UnaryStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
-  """A controllable implementation of a unary-stream RPC method."""
-
-  @abc.abstractmethod
-  def service(self, request, response_consumer, context, control):
-    """Services an RPC that takes one message and produces a stream of messages.
-
-    Args:
-      request: The single request message for the RPC.
-      response_consumer: A stream.Consumer to be called to accept the response
-        messages of the RPC.
-      context: A face_interfaces.RpcContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-    raise NotImplementedError()
-
-
-class UnaryStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
-  """A type for unary-request-stream-response message pairings."""
-
-  @abc.abstractmethod
-  def request(self):
-    """Affords a request message.
-
-    Implementations of this method should return a different message with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A request message.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def verify(self, request, responses, test_case):
-    """Verifies that the computed responses match the given request.
-
-    Args:
-      request: A request message.
-      responses: A sequence of response messages.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the request and responses do not match, indicating that
-        there was some problem executing the RPC under test.
-    """
-    raise NotImplementedError()
-
-
-class StreamUnaryTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
-  """A controllable implementation of a stream-unary RPC method."""
-
-  @abc.abstractmethod
-  def service(self, response_callback, context, control):
-    """Services an RPC that takes a stream of messages and produces one message.
-
-    Args:
-      response_callback: A callback to be called to accept the response message
-        of the RPC.
-      context: A face_interfaces.RpcContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Returns:
-      A stream.Consumer with which to accept the request messages of the RPC.
-        The consumer returned from this method may or may not be invoked to
-        completion: in the case of RPC abortion, RPC Framework will simply stop
-        passing messages to this object. Implementations must not assume that
-        this object will be called to completion of the request stream or even
-        called at all.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-    raise NotImplementedError()
-
-
-class StreamUnaryTestMessages(six.with_metaclass(abc.ABCMeta)):
-  """A type for stream-request-unary-response message pairings."""
-
-  @abc.abstractmethod
-  def requests(self):
-    """Affords a sequence of request messages.
-
-    Implementations of this method should return a different sequences with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A sequence of request messages.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def verify(self, requests, response, test_case):
-    """Verifies that the computed response matches the given requests.
-
-    Args:
-      requests: A sequence of request messages.
-      response: A response message.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the requests and response do not match, indicating that
-        there was some problem executing the RPC under test.
-    """
-    raise NotImplementedError()
-
-
-class StreamStreamTestMethodImplementation(six.with_metaclass(abc.ABCMeta, interfaces.Method)):
-  """A controllable implementation of a stream-stream RPC method."""
-
-  @abc.abstractmethod
-  def service(self, response_consumer, context, control):
-    """Services an RPC that accepts and produces streams of messages.
-
-    Args:
-      response_consumer: A stream.Consumer to be called to accept the response
-        messages of the RPC.
-      context: A face_interfaces.RpcContext object.
-      control: A test_control.Control to control execution of this method.
-
-    Returns:
-      A stream.Consumer with which to accept the request messages of the RPC.
-        The consumer returned from this method may or may not be invoked to
-        completion: in the case of RPC abortion, RPC Framework will simply stop
-        passing messages to this object. Implementations must not assume that
-        this object will be called to completion of the request stream or even
-        called at all.
-
-    Raises:
-      abandonment.Abandoned: May or may not be raised when the RPC has been
-        aborted.
-    """
-    raise NotImplementedError()
-
-
-class StreamStreamTestMessages(six.with_metaclass(abc.ABCMeta)):
-  """A type for stream-request-stream-response message pairings."""
-
-  @abc.abstractmethod
-  def requests(self):
-    """Affords a sequence of request messages.
-
-    Implementations of this method should return a different sequences with each
-    call so that multiple test executions of the test method may be made with
-    different inputs.
-
-    Returns:
-      A sequence of request messages.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def verify(self, requests, responses, test_case):
-    """Verifies that the computed response matches the given requests.
-
-    Args:
-      requests: A sequence of request messages.
-      responses: A sequence of response messages.
-      test_case: A unittest.TestCase object affording useful assertion methods.
-
-    Raises:
-      AssertionError: If the requests and responses do not match, indicating
-        that there was some problem executing the RPC under test.
-    """
-    raise NotImplementedError()
-
-
-class TestService(six.with_metaclass(abc.ABCMeta)):
-  """A specification of implemented RPC methods to use in tests."""
-
-  @abc.abstractmethod
-  def name(self):
-    """Identifies the RPC service name used during the test.
-
-    Returns:
-      The RPC service name to be used for the test.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def unary_unary_scenarios(self):
-    """Affords unary-request-unary-response test methods and their messages.
-
-    Returns:
-      A dict from method name to pair. The first element of the pair
-        is a UnaryUnaryTestMethodImplementation object and the second element
-        is a sequence of UnaryUnaryTestMethodMessages objects.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def unary_stream_scenarios(self):
-    """Affords unary-request-stream-response test methods and their messages.
-
-    Returns:
-      A dict from method name to pair. The first element of the pair is a
-        UnaryStreamTestMethodImplementation object and the second element is a
-        sequence of UnaryStreamTestMethodMessages objects.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def stream_unary_scenarios(self):
-    """Affords stream-request-unary-response test methods and their messages.
-
-    Returns:
-      A dict from method name to pair. The first element of the pair is a
-        StreamUnaryTestMethodImplementation object and the second element is a
-        sequence of StreamUnaryTestMethodMessages objects.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def stream_stream_scenarios(self):
-    """Affords stream-request-stream-response test methods and their messages.
-
-    Returns:
-      A dict from method name to pair. The first element of the pair is a
-        StreamStreamTestMethodImplementation object and the second element is a
-        sequence of StreamStreamTestMethodMessages objects.
-    """
-    raise NotImplementedError()
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py b/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
deleted file mode 100644
index 117c723..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/stock_service.py
+++ /dev/null
@@ -1,374 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Examples of Python implementations of the stock.proto Stock service."""
-
-from grpc.framework.common import cardinality
-from grpc.framework.foundation import abandonment
-from grpc.framework.foundation import stream
-from grpc.framework.foundation import stream_util
-from tests.unit.framework.face.testing import service
-from tests.unit._junkdrawer import stock_pb2
-
-SYMBOL_FORMAT = 'test symbol:%03d'
-STREAM_LENGTH = 400
-
-# A test-appropriate security-pricing function. :-P
-_price = lambda symbol_name: float(hash(symbol_name) % 4096)
-
-
-def _get_last_trade_price(stock_request, stock_reply_callback, control, active):
-  """A unary-request, unary-response test method."""
-  control.control()
-  if active():
-    stock_reply_callback(
-        stock_pb2.StockReply(
-            symbol=stock_request.symbol, price=_price(stock_request.symbol)))
-  else:
-    raise abandonment.Abandoned()
-
-
-def _get_last_trade_price_multiple(stock_reply_consumer, control, active):
-  """A stream-request, stream-response test method."""
-  def stock_reply_for_stock_request(stock_request):
-    control.control()
-    if active():
-      return stock_pb2.StockReply(
-          symbol=stock_request.symbol, price=_price(stock_request.symbol))
-    else:
-      raise abandonment.Abandoned()
-  return stream_util.TransformingConsumer(
-      stock_reply_for_stock_request, stock_reply_consumer)
-
-
-def _watch_future_trades(stock_request, stock_reply_consumer, control, active):
-  """A unary-request, stream-response test method."""
-  base_price = _price(stock_request.symbol)
-  for index in range(stock_request.num_trades_to_watch):
-    control.control()
-    if active():
-      stock_reply_consumer.consume(
-          stock_pb2.StockReply(
-              symbol=stock_request.symbol, price=base_price + index))
-    else:
-      raise abandonment.Abandoned()
-  stock_reply_consumer.terminate()
-
-
-def _get_highest_trade_price(stock_reply_callback, control, active):
-  """A stream-request, unary-response test method."""
-
-  class StockRequestConsumer(stream.Consumer):
-    """Keeps an ongoing record of the most valuable symbol yet consumed."""
-
-    def __init__(self):
-      self._symbol = None
-      self._price = None
-
-    def consume(self, stock_request):
-      control.control()
-      if active():
-        if self._price is None:
-          self._symbol = stock_request.symbol
-          self._price = _price(stock_request.symbol)
-        else:
-          candidate_price = _price(stock_request.symbol)
-          if self._price < candidate_price:
-            self._symbol = stock_request.symbol
-            self._price = candidate_price
-
-    def terminate(self):
-      control.control()
-      if active():
-        if self._symbol is None:
-          raise ValueError()
-        else:
-          stock_reply_callback(
-              stock_pb2.StockReply(symbol=self._symbol, price=self._price))
-          self._symbol = None
-          self._price = None
-
-    def consume_and_terminate(self, stock_request):
-      control.control()
-      if active():
-        if self._price is None:
-          stock_reply_callback(
-              stock_pb2.StockReply(
-                  symbol=stock_request.symbol,
-                  price=_price(stock_request.symbol)))
-        else:
-          candidate_price = _price(stock_request.symbol)
-          if self._price < candidate_price:
-            stock_reply_callback(
-                stock_pb2.StockReply(
-                    symbol=stock_request.symbol, price=candidate_price))
-          else:
-            stock_reply_callback(
-                stock_pb2.StockReply(
-                    symbol=self._symbol, price=self._price))
-
-        self._symbol = None
-        self._price = None
-
-  return StockRequestConsumer()
-
-
-class GetLastTradePrice(service.UnaryUnaryTestMethodImplementation):
-  """GetLastTradePrice for use in tests."""
-
-  def name(self):
-    return 'GetLastTradePrice'
-
-  def cardinality(self):
-    return cardinality.Cardinality.UNARY_UNARY
-
-  def request_class(self):
-    return stock_pb2.StockRequest
-
-  def response_class(self):
-    return stock_pb2.StockReply
-
-  def serialize_request(self, request):
-    return request.SerializeToString()
-
-  def deserialize_request(self, serialized_request):
-    return stock_pb2.StockRequest.FromString(serialized_request)
-
-  def serialize_response(self, response):
-    return response.SerializeToString()
-
-  def deserialize_response(self, serialized_response):
-    return stock_pb2.StockReply.FromString(serialized_response)
-
-  def service(self, request, response_callback, context, control):
-    _get_last_trade_price(
-        request, response_callback, control, context.is_active)
-
-
-class GetLastTradePriceMessages(service.UnaryUnaryTestMessages):
-
-  def __init__(self):
-    self._index = 0
-
-  def request(self):
-    symbol = SYMBOL_FORMAT % self._index
-    self._index += 1
-    return stock_pb2.StockRequest(symbol=symbol)
-
-  def verify(self, request, response, test_case):
-    test_case.assertEqual(request.symbol, response.symbol)
-    test_case.assertEqual(_price(request.symbol), response.price)
-
-
-class GetLastTradePriceMultiple(service.StreamStreamTestMethodImplementation):
-  """GetLastTradePriceMultiple for use in tests."""
-
-  def name(self):
-    return 'GetLastTradePriceMultiple'
-
-  def cardinality(self):
-    return cardinality.Cardinality.STREAM_STREAM
-
-  def request_class(self):
-    return stock_pb2.StockRequest
-
-  def response_class(self):
-    return stock_pb2.StockReply
-
-  def serialize_request(self, request):
-    return request.SerializeToString()
-
-  def deserialize_request(self, serialized_request):
-    return stock_pb2.StockRequest.FromString(serialized_request)
-
-  def serialize_response(self, response):
-    return response.SerializeToString()
-
-  def deserialize_response(self, serialized_response):
-    return stock_pb2.StockReply.FromString(serialized_response)
-
-  def service(self, response_consumer, context, control):
-    return _get_last_trade_price_multiple(
-        response_consumer, control, context.is_active)
-
-
-class GetLastTradePriceMultipleMessages(service.StreamStreamTestMessages):
-  """Pairs of message streams for use with GetLastTradePriceMultiple."""
-
-  def __init__(self):
-    self._index = 0
-
-  def requests(self):
-    base_index = self._index
-    self._index += 1
-    return [
-        stock_pb2.StockRequest(symbol=SYMBOL_FORMAT % (base_index + index))
-        for index in range(STREAM_LENGTH)]
-
-  def verify(self, requests, responses, test_case):
-    test_case.assertEqual(len(requests), len(responses))
-    for stock_request, stock_reply in zip(requests, responses):
-      test_case.assertEqual(stock_request.symbol, stock_reply.symbol)
-      test_case.assertEqual(_price(stock_request.symbol), stock_reply.price)
-
-
-class WatchFutureTrades(service.UnaryStreamTestMethodImplementation):
-  """WatchFutureTrades for use in tests."""
-
-  def name(self):
-    return 'WatchFutureTrades'
-
-  def cardinality(self):
-    return cardinality.Cardinality.UNARY_STREAM
-
-  def request_class(self):
-    return stock_pb2.StockRequest
-
-  def response_class(self):
-    return stock_pb2.StockReply
-
-  def serialize_request(self, request):
-    return request.SerializeToString()
-
-  def deserialize_request(self, serialized_request):
-    return stock_pb2.StockRequest.FromString(serialized_request)
-
-  def serialize_response(self, response):
-    return response.SerializeToString()
-
-  def deserialize_response(self, serialized_response):
-    return stock_pb2.StockReply.FromString(serialized_response)
-
-  def service(self, request, response_consumer, context, control):
-    _watch_future_trades(request, response_consumer, control, context.is_active)
-
-
-class WatchFutureTradesMessages(service.UnaryStreamTestMessages):
-  """Pairs of a single request message and a sequence of response messages."""
-
-  def __init__(self):
-    self._index = 0
-
-  def request(self):
-    symbol = SYMBOL_FORMAT % self._index
-    self._index += 1
-    return stock_pb2.StockRequest(
-        symbol=symbol, num_trades_to_watch=STREAM_LENGTH)
-
-  def verify(self, request, responses, test_case):
-    test_case.assertEqual(STREAM_LENGTH, len(responses))
-    base_price = _price(request.symbol)
-    for index, response in enumerate(responses):
-      test_case.assertEqual(base_price + index, response.price)
-
-
-class GetHighestTradePrice(service.StreamUnaryTestMethodImplementation):
-  """GetHighestTradePrice for use in tests."""
-
-  def name(self):
-    return 'GetHighestTradePrice'
-
-  def cardinality(self):
-    return cardinality.Cardinality.STREAM_UNARY
-
-  def request_class(self):
-    return stock_pb2.StockRequest
-
-  def response_class(self):
-    return stock_pb2.StockReply
-
-  def serialize_request(self, request):
-    return request.SerializeToString()
-
-  def deserialize_request(self, serialized_request):
-    return stock_pb2.StockRequest.FromString(serialized_request)
-
-  def serialize_response(self, response):
-    return response.SerializeToString()
-
-  def deserialize_response(self, serialized_response):
-    return stock_pb2.StockReply.FromString(serialized_response)
-
-  def service(self, response_callback, context, control):
-    return _get_highest_trade_price(
-        response_callback, control, context.is_active)
-
-
-class GetHighestTradePriceMessages(service.StreamUnaryTestMessages):
-
-  def requests(self):
-    return [
-        stock_pb2.StockRequest(symbol=SYMBOL_FORMAT % index)
-        for index in range(STREAM_LENGTH)]
-
-  def verify(self, requests, response, test_case):
-    price = None
-    symbol = None
-    for stock_request in requests:
-      current_symbol = stock_request.symbol
-      current_price = _price(current_symbol)
-      if price is None or price < current_price:
-        price = current_price
-        symbol = current_symbol
-    test_case.assertEqual(price, response.price)
-    test_case.assertEqual(symbol, response.symbol)
-
-
-class StockTestService(service.TestService):
-  """A corpus of test data with one method of each RPC cardinality."""
-
-  def name(self):
-    return 'Stock'
-
-  def unary_unary_scenarios(self):
-    return {
-        'GetLastTradePrice': (
-            GetLastTradePrice(), [GetLastTradePriceMessages()]),
-    }
-
-  def unary_stream_scenarios(self):
-    return {
-        'WatchFutureTrades': (
-            WatchFutureTrades(), [WatchFutureTradesMessages()]),
-    }
-
-  def stream_unary_scenarios(self):
-    return {
-        'GetHighestTradePrice': (
-            GetHighestTradePrice(), [GetHighestTradePriceMessages()])
-    }
-
-  def stream_stream_scenarios(self):
-    return {
-        'GetLastTradePriceMultiple': (
-            GetLastTradePriceMultiple(), [GetLastTradePriceMultipleMessages()]),
-    }
-
-
-STOCK_TEST_SERVICE = StockTestService()
diff --git a/src/python/grpcio/tests/unit/framework/face/testing/test_case.py b/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
deleted file mode 100644
index f29d400..0000000
--- a/src/python/grpcio/tests/unit/framework/face/testing/test_case.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Tools for creating tests of implementations of the Face layer."""
-
-import abc
-
-import six
-
-# face_interfaces and interfaces are referenced in specification in this module.
-from grpc.framework.face import interfaces as face_interfaces  # pylint: disable=unused-import
-from tests.unit.framework.face.testing import interfaces  # pylint: disable=unused-import
-
-
-class FaceTestCase(six.with_metaclass(abc.ABCMeta)):
-  """Describes a test of the Face Layer of RPC Framework.
-
-  Concrete subclasses must also inherit from unittest.TestCase and from at least
-  one class that defines test methods.
-  """
-
-  @abc.abstractmethod
-  def set_up_implementation(
-      self, name, methods, method_implementations,
-      multi_method_implementation):
-    """Instantiates the Face Layer implementation under test.
-
-    Args:
-      name: The service name to be used in the test.
-      methods: A sequence of interfaces.Method objects describing the RPC
-        methods that will be called during the test.
-      method_implementations: A dictionary from string RPC method name to
-        face_interfaces.MethodImplementation object specifying
-        implementation of an RPC method.
-      multi_method_implementation: An face_interfaces.MultiMethodImplementation
-        or None.
-
-    Returns:
-      A sequence of length two the first element of which is a
-        face_interfaces.GenericStub (backed by the given method
-        implementations), and the second element of which is an arbitrary memo
-        object to be kept and passed to tearDownImplementation at the conclusion
-        of the test.
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def tear_down_implementation(self, memo):
-    """Destroys the Face layer implementation under test.
-
-    Args:
-      memo: The object from the second position of the return value of
-        set_up_implementation.
-    """
-    raise NotImplementedError()
diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
index 10391bc..09bd309 100644
--- a/src/ruby/ext/grpc/rb_channel_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <string.h>
+
 #include <ruby/ruby.h>
 #include "rb_grpc_imports.generated.h"
 #include "rb_channel_credentials.h"
@@ -39,6 +41,7 @@
 
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include "rb_call_credentials.h"
@@ -48,6 +51,8 @@
    grpc_channel_credentials. */
 static VALUE grpc_rb_cChannelCredentials = Qnil;
 
+static char *pem_root_certs = NULL;
+
 /* grpc_rb_channel_credentials wraps a grpc_channel_credentials.  It provides a
  * mark object that is used to hold references to any objects used to create
  * the credentials. */
@@ -236,6 +241,25 @@
   return grpc_rb_wrap_channel_credentials(creds, mark);
 }
 
+static grpc_ssl_roots_override_result get_ssl_roots_override(
+    char **pem_root_certs_ptr) {
+  *pem_root_certs_ptr = pem_root_certs;
+  if (pem_root_certs == NULL) {
+    return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+  } else {
+    return GRPC_SSL_ROOTS_OVERRIDE_OK;
+  }
+}
+
+static VALUE grpc_rb_set_default_roots_pem(VALUE self, VALUE roots) {
+  char *roots_ptr = StringValueCStr(roots);
+  size_t length = strlen(roots_ptr);
+  (void)self;
+  pem_root_certs = gpr_malloc((length + 1) * sizeof(char));
+  memcpy(pem_root_certs, roots_ptr, length + 1);
+  return Qnil;
+}
+
 void Init_grpc_channel_credentials() {
   grpc_rb_cChannelCredentials =
       rb_define_class_under(grpc_rb_mGrpcCore, "ChannelCredentials", rb_cObject);
@@ -251,6 +275,11 @@
                    grpc_rb_channel_credentials_init_copy, 1);
   rb_define_method(grpc_rb_cChannelCredentials, "compose",
                    grpc_rb_channel_credentials_compose, -1);
+  rb_define_module_function(grpc_rb_cChannelCredentials,
+                            "set_default_roots_pem",
+                            grpc_rb_set_default_roots_pem, 1);
+
+  grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
 
   id_pem_cert_chain = rb_intern("__pem_cert_chain");
   id_pem_private_key = rb_intern("__pem_private_key");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 16ecb66..3b18e41 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -125,6 +125,7 @@
 grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
 grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
 grpc_is_binary_header_type grpc_is_binary_header_import;
+grpc_call_error_to_string_type grpc_call_error_to_string_import;
 grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
 grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
 grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
@@ -391,6 +392,7 @@
   grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
   grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
   grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
+  grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string");
   grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
   grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
   grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index b260042..f2f118a 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -325,6 +325,9 @@
 typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
 extern grpc_is_binary_header_type grpc_is_binary_header_import;
 #define grpc_is_binary_header grpc_is_binary_header_import
+typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error);
+extern grpc_call_error_to_string_type grpc_call_error_to_string_import;
+#define grpc_call_error_to_string grpc_call_error_to_string_import
 typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
 extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
 #define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb
index a56c49f..79fa705 100644
--- a/src/ruby/lib/grpc.rb
+++ b/src/ruby/lib/grpc.rb
@@ -28,9 +28,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 ssl_roots_path = File.expand_path('../../../../etc/roots.pem', __FILE__)
-unless ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH']
-  ENV['GRPC_DEFAULT_SSL_ROOTS_FILE_PATH'] = ssl_roots_path
-end
 
 require_relative 'grpc/errors'
 require_relative 'grpc/grpc'
@@ -42,3 +39,11 @@
 require_relative 'grpc/generic/client_stub'
 require_relative 'grpc/generic/service'
 require_relative 'grpc/generic/rpc_server'
+
+begin
+  file = File.open(ssl_roots_path)
+  roots = file.read
+  GRPC::Core::ChannelCredentials.set_default_roots_pem roots
+ensure
+  file.close
+end
diff --git a/templates/src/node/tools/package.json.template b/templates/src/node/tools/package.json.template
index c69de7c..4f673c4 100644
--- a/templates/src/node/tools/package.json.template
+++ b/templates/src/node/tools/package.json.template
@@ -18,7 +18,8 @@
       }
     ],
     "bin": {
-      "grpc-tools-protoc": "./bin/protoc.js"
+      "grpc-tools-protoc": "./bin/protoc.js",
+      "grpc-tools-plugin": "./bin/protoc_plugin.js"
     },
     "scripts": {
       "install": "./node_modules/.bin/node-pre-gyp install"
@@ -34,6 +35,7 @@
     "files": [
       "index.js",
       "bin/protoc.js",
+      "bin/protoc_plugin.js",
       "LICENSE"
     ],
     "main": "index.js"
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
new file mode 100644
index 0000000..4cb8d3b
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../csharp_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
new file mode 100644
index 0000000..e39175a
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
new file mode 100644
index 0000000..542c81d
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM golang:1.5
+  
+  <%include file="../../go_path.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
new file mode 100644
index 0000000..542c81d
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile.template
@@ -0,0 +1,37 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM golang:1.5
+  
+  <%include file="../../go_path.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
new file mode 100644
index 0000000..c286e80
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile.template
@@ -0,0 +1,44 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../java_deps.include"/>
+  
+  # Trigger download of as many Gradle artifacts as possible.
+  RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && ${'\\'}
+    cd grpc-java && ${'\\'}
+    ./gradlew :grpc-interop-testing:installDist -PskipCodegen=true && ${'\\'}
+    rm -r "$(pwd)"
+  
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
new file mode 100644
index 0000000..89bb9ac
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../node_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
new file mode 100644
index 0000000..476f9d3
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile.template
@@ -0,0 +1,64 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../ruby_deps.include"/>
+  <%include file="../../php_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # ronn: a ruby tool used to convert markdown to man pages, used during the
+  # install of Protobuf extensions
+  #
+  # rake: a ruby version of make used to build the PHP Protobuf extension
+  RUN /bin/bash -l -c "rvm all do gem install ronn rake"
+  
+  # Install composer
+  RUN curl -sS https://getcomposer.org/installer | php
+  RUN mv composer.phar /usr/local/bin/composer
+  
+  # As an attempt to work around #4212, try to prefetch Protobuf-PHP dependency
+  # into composer cache to prevent "composer install" from cloning on each build.
+  RUN git clone --mirror https://github.com/stanley-cheung/Protobuf-PHP.git ${'\\'}
+    /root/.composer/cache/vcs/git-github.com-stanley-cheung-Protobuf-PHP.git/
+  
+  # Download the patched PHP protobuf so that PHP gRPC clients can be generated
+  # from proto3 schemas.
+  RUN git clone https://github.com/stanley-cheung/Protobuf-PHP.git /var/local/git/protobuf-php
+  
+  RUN /bin/bash -l -c "rvm use ruby-2.1 ${'\\'}
+    && cd /var/local/git/protobuf-php ${'\\'}
+    && rvm all do rake pear:package version=1.0 ${'\\'}
+    && pear install Protobuf-1.0.tgz"
+  
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
new file mode 100644
index 0000000..4e816ce
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
new file mode 100644
index 0000000..c3625b9
--- /dev/null
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../ruby_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index 81e3927..1a5594b 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -62,8 +62,8 @@
 static void channel_destroy_func(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem) {}
 
-static void call_destroy_func(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {
+static void call_destroy_func(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *ignored) {
   ++*(int *)(elem->channel_data);
 }
 
@@ -87,7 +87,7 @@
 }
 
 static void free_call(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
-  grpc_call_stack_destroy(exec_ctx, arg);
+  grpc_call_stack_destroy(exec_ctx, arg, NULL);
   gpr_free(arg);
 }
 
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/04a5f10d2ebc712cf13c05b5ed0fafb31b42737c b/test/core/end2end/fuzzers/api_fuzzer_corpus/04a5f10d2ebc712cf13c05b5ed0fafb31b42737c
new file mode 100644
index 0000000..d46856d
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/04a5f10d2ebc712cf13c05b5ed0fafb31b42737c
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/38a55e83e685617cdf72e95f1303857b627ae346 b/test/core/end2end/fuzzers/api_fuzzer_corpus/38a55e83e685617cdf72e95f1303857b627ae346
new file mode 100644
index 0000000..3c8c2c1
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/38a55e83e685617cdf72e95f1303857b627ae346
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/40b4b92460c4e76a39af9042fb3d86d491a98e16 b/test/core/end2end/fuzzers/api_fuzzer_corpus/40b4b92460c4e76a39af9042fb3d86d491a98e16
new file mode 100644
index 0000000..44a2b9e
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/40b4b92460c4e76a39af9042fb3d86d491a98e16
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/6914f5f380c83ff9e3e90fc60d5048e47e5e77d9 b/test/core/end2end/fuzzers/api_fuzzer_corpus/6914f5f380c83ff9e3e90fc60d5048e47e5e77d9
new file mode 100644
index 0000000..da0c78e
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/6914f5f380c83ff9e3e90fc60d5048e47e5e77d9
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/7abe8c414aa1418157c2d7ae5e70a84ffb61c027 b/test/core/end2end/fuzzers/api_fuzzer_corpus/7abe8c414aa1418157c2d7ae5e70a84ffb61c027
new file mode 100644
index 0000000..6b06ce2
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/7abe8c414aa1418157c2d7ae5e70a84ffb61c027
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/8c5bbcc6935d43c94a0c4ce4a5da01c04fd223d8 b/test/core/end2end/fuzzers/api_fuzzer_corpus/8c5bbcc6935d43c94a0c4ce4a5da01c04fd223d8
new file mode 100644
index 0000000..a0b621b
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/8c5bbcc6935d43c94a0c4ce4a5da01c04fd223d8
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/b5bcc7f39420e997ec6f8e3c70ef49b8f1afb361 b/test/core/end2end/fuzzers/api_fuzzer_corpus/b5bcc7f39420e997ec6f8e3c70ef49b8f1afb361
new file mode 100644
index 0000000..80aa9b8
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/b5bcc7f39420e997ec6f8e3c70ef49b8f1afb361
Binary files differ
diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/f755b44ff2221c971ca2bfaffc69e002ba982730 b/test/core/end2end/fuzzers/api_fuzzer_corpus/f755b44ff2221c971ca2bfaffc69e002ba982730
new file mode 100644
index 0000000..32dab3b
--- /dev/null
+++ b/test/core/end2end/fuzzers/api_fuzzer_corpus/f755b44ff2221c971ca2bfaffc69e002ba982730
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1e64080289ea4168304417f3fbd86b01d7d6f431 b/test/core/end2end/fuzzers/client_fuzzer_corpus/1e64080289ea4168304417f3fbd86b01d7d6f431
new file mode 100644
index 0000000..374b283
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1e64080289ea4168304417f3fbd86b01d7d6f431
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/20ee437b7f456ebb19d98d94d9feb1d5e9174c65 b/test/core/end2end/fuzzers/client_fuzzer_corpus/20ee437b7f456ebb19d98d94d9feb1d5e9174c65
new file mode 100644
index 0000000..29243f9
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/20ee437b7f456ebb19d98d94d9feb1d5e9174c65
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2c1ecf05c5dde692ed16502294e9570ac3b02600 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2c1ecf05c5dde692ed16502294e9570ac3b02600
new file mode 100644
index 0000000..0f30385
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2c1ecf05c5dde692ed16502294e9570ac3b02600
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/aa878edb0100e876e00e310ae221b220fdb5e028 b/test/core/end2end/fuzzers/client_fuzzer_corpus/aa878edb0100e876e00e310ae221b220fdb5e028
new file mode 100644
index 0000000..bc6a444
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/aa878edb0100e876e00e310ae221b220fdb5e028
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/slow-unit-53cf4d25741d5f6e7ad9147b286ff0b40cb500a9 b/test/core/end2end/fuzzers/client_fuzzer_corpus/slow-unit-53cf4d25741d5f6e7ad9147b286ff0b40cb500a9
new file mode 100644
index 0000000..997b3d3
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/slow-unit-53cf4d25741d5f6e7ad9147b286ff0b40cb500a9
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/03a304b82629155af693978c2b53439e553f6450 b/test/core/end2end/fuzzers/server_fuzzer_corpus/03a304b82629155af693978c2b53439e553f6450
new file mode 100644
index 0000000..d4072c6
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/03a304b82629155af693978c2b53439e553f6450
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/052c8f28e5884bb48f0d504461272cd3a5893215 b/test/core/end2end/fuzzers/server_fuzzer_corpus/052c8f28e5884bb48f0d504461272cd3a5893215
new file mode 100644
index 0000000..5cbafc4
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/052c8f28e5884bb48f0d504461272cd3a5893215
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/2c4c7e2ed6d977ec119b040b328ad09808909a70 b/test/core/end2end/fuzzers/server_fuzzer_corpus/2c4c7e2ed6d977ec119b040b328ad09808909a70
new file mode 100644
index 0000000..1d73a92
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/2c4c7e2ed6d977ec119b040b328ad09808909a70
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/4d982c41efad2242f8c06630c23c68146153b47b b/test/core/end2end/fuzzers/server_fuzzer_corpus/4d982c41efad2242f8c06630c23c68146153b47b
new file mode 100644
index 0000000..fa1d5f0
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/4d982c41efad2242f8c06630c23c68146153b47b
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/830e3f794c53f7b284eb5c635b2943db9ee9aaee b/test/core/end2end/fuzzers/server_fuzzer_corpus/830e3f794c53f7b284eb5c635b2943db9ee9aaee
new file mode 100644
index 0000000..366077e
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/830e3f794c53f7b284eb5c635b2943db9ee9aaee
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-0aa52e00ddd54f8e129430852c2da95650c354b0 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-0aa52e00ddd54f8e129430852c2da95650c354b0
new file mode 100644
index 0000000..15d6f17
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-0aa52e00ddd54f8e129430852c2da95650c354b0
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-3cec540a680b108dda1e0a8e0bfb2d44e5a4a4e8 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-3cec540a680b108dda1e0a8e0bfb2d44e5a4a4e8
new file mode 100644
index 0000000..ca94f4b
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-3cec540a680b108dda1e0a8e0bfb2d44e5a4a4e8
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-84f22ffca68c6e1590a44aa9f6dd0cef1f680c77 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-84f22ffca68c6e1590a44aa9f6dd0cef1f680c77
new file mode 100644
index 0000000..9e7b002
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-84f22ffca68c6e1590a44aa9f6dd0cef1f680c77
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-adaac86cf1aa1e98e95240c5f92c3708456c3624 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-adaac86cf1aa1e98e95240c5f92c3708456c3624
new file mode 100644
index 0000000..c525f76
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-adaac86cf1aa1e98e95240c5f92c3708456c3624
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-b281f018cc919301131cf3ed28449cfbd24b6bbf b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-b281f018cc919301131cf3ed28449cfbd24b6bbf
new file mode 100644
index 0000000..380cd87
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-b281f018cc919301131cf3ed28449cfbd24b6bbf
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba0016a62a8576a57f000b90c364847ef6b12dcc b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba0016a62a8576a57f000b90c364847ef6b12dcc
new file mode 100644
index 0000000..cbd1829
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba0016a62a8576a57f000b90c364847ef6b12dcc
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba17346b8e46e6a05aaa7342a959a7c5ab0f1471 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba17346b8e46e6a05aaa7342a959a7c5ab0f1471
new file mode 100644
index 0000000..3f5b839
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba17346b8e46e6a05aaa7342a959a7c5ab0f1471
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ccafab6afdc6474610023b47bd7b3e1b9ea4647b b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ccafab6afdc6474610023b47bd7b3e1b9ea4647b
new file mode 100644
index 0000000..65737bf
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ccafab6afdc6474610023b47bd7b3e1b9ea4647b
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-dc57e96cd02ba32fa4a99c97b6490e9879d30be5 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-dc57e96cd02ba32fa4a99c97b6490e9879d30be5
new file mode 100644
index 0000000..6c4ed6d
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-dc57e96cd02ba32fa4a99c97b6490e9879d30be5
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f6c1042f96e15183dcc13b9658d971cc29426d53 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f6c1042f96e15183dcc13b9658d971cc29426d53
new file mode 100644
index 0000000..414dc69
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f6c1042f96e15183dcc13b9658d971cc29426d53
Binary files differ
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f9a2773d6502fd4b1ffa73df3c550b0da63af833 b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f9a2773d6502fd4b1ffa73df3c550b0da63af833
new file mode 100644
index 0000000..bf38fac
--- /dev/null
+++ b/test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f9a2773d6502fd4b1ffa73df3c550b0da63af833
Binary files differ
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index 9f9ee85..99049aa 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -232,8 +232,8 @@
 static void init_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
                            grpc_call_element_args *args) {}
 
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                              void *and_free_memory) {}
 
 static void init_channel_elem(grpc_exec_ctx *exec_ctx,
                               grpc_channel_element *elem,
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index 04671fb..f287a5a 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -84,49 +84,37 @@
     int test_id, const grpc::string& server_address,
     std::shared_ptr<Channel> channel,
     const WeightedRandomTestSelector& test_selector, long test_duration_secs,
-    long sleep_duration_ms, long metrics_collection_interval_secs)
+    long sleep_duration_ms)
     : test_id_(test_id),
       server_address_(server_address),
       channel_(channel),
       interop_client_(new InteropClient(channel, false)),
       test_selector_(test_selector),
       test_duration_secs_(test_duration_secs),
-      sleep_duration_ms_(sleep_duration_ms),
-      metrics_collection_interval_secs_(metrics_collection_interval_secs) {}
+      sleep_duration_ms_(sleep_duration_ms) {}
 
-void StressTestInteropClient::MainLoop(std::shared_ptr<Gauge> qps_gauge) {
+void StressTestInteropClient::MainLoop(std::shared_ptr<QpsGauge> qps_gauge) {
   gpr_log(GPR_INFO, "Running test %d. ServerAddr: %s", test_id_,
           server_address_.c_str());
 
-  gpr_timespec test_end_time =
-      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
-                   gpr_time_from_seconds(test_duration_secs_, GPR_TIMESPAN));
+  gpr_timespec test_end_time;
+  if (test_duration_secs_ < 0) {
+    test_end_time = gpr_inf_future(GPR_CLOCK_REALTIME);
+  } else {
+    test_end_time =
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                     gpr_time_from_seconds(test_duration_secs_, GPR_TIMESPAN));
+  }
 
-  gpr_timespec current_time = gpr_now(GPR_CLOCK_REALTIME);
-  gpr_timespec next_stat_collection_time = current_time;
-  gpr_timespec collection_interval =
-      gpr_time_from_seconds(metrics_collection_interval_secs_, GPR_TIMESPAN);
-  long num_calls_per_interval = 0;
+  qps_gauge->Reset();
 
-  while (test_duration_secs_ < 0 ||
-         gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), test_end_time) < 0) {
+  while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), test_end_time) < 0) {
     // Select the test case to execute based on the weights and execute it
     TestCaseType test_case = test_selector_.GetNextTest();
     gpr_log(GPR_DEBUG, "%d - Executing the test case %d", test_id_, test_case);
     RunTest(test_case);
 
-    num_calls_per_interval++;
-
-    // See if its time to collect stats yet
-    current_time = gpr_now(GPR_CLOCK_REALTIME);
-    if (gpr_time_cmp(next_stat_collection_time, current_time) < 0) {
-      qps_gauge->Set(num_calls_per_interval /
-                     metrics_collection_interval_secs_);
-
-      num_calls_per_interval = 0;
-      next_stat_collection_time =
-          gpr_time_add(current_time, collection_interval);
-    }
+    qps_gauge->Incr();
 
     // Sleep between successive calls if needed
     if (sleep_duration_ms_ > 0) {
diff --git a/test/cpp/interop/stress_interop_client.h b/test/cpp/interop/stress_interop_client.h
index 6fd303d..cb0cd98 100644
--- a/test/cpp/interop/stress_interop_client.h
+++ b/test/cpp/interop/stress_interop_client.h
@@ -87,12 +87,11 @@
   StressTestInteropClient(int test_id, const grpc::string& server_address,
                           std::shared_ptr<Channel> channel,
                           const WeightedRandomTestSelector& test_selector,
-                          long test_duration_secs, long sleep_duration_ms,
-                          long metrics_collection_interval_secs);
+                          long test_duration_secs, long sleep_duration_ms);
 
   // The main function. Use this as the thread entry point.
-  // qps_gauge is the Gauge to record the requests per second metric
-  void MainLoop(std::shared_ptr<Gauge> qps_gauge);
+  // qps_gauge is the QpsGauge to record the requests per second metric
+  void MainLoop(std::shared_ptr<QpsGauge> qps_gauge);
 
  private:
   void RunTest(TestCaseType test_case);
@@ -104,7 +103,6 @@
   const WeightedRandomTestSelector& test_selector_;
   long test_duration_secs_;
   long sleep_duration_ms_;
-  long metrics_collection_interval_secs_;
 };
 
 }  // namespace testing
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 38caf31..d9e3fd2 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -56,9 +56,6 @@
 
 DEFINE_int32(metrics_port, 8081, "The metrics server port.");
 
-DEFINE_int32(metrics_collection_interval_secs, 5,
-             "How often (in seconds) should metrics be recorded.");
-
 DEFINE_int32(sleep_duration_ms, 0,
              "The duration (in millisec) between two"
              " consecutive test calls (per server) issued by the server.");
@@ -275,19 +272,19 @@
            stub_idx++) {
         StressTestInteropClient* client = new StressTestInteropClient(
             ++thread_idx, *it, channel, test_selector, FLAGS_test_duration_secs,
-            FLAGS_sleep_duration_ms, FLAGS_metrics_collection_interval_secs);
+            FLAGS_sleep_duration_ms);
 
-        bool is_already_created;
-        // Gauge name
+        bool is_already_created = false;
+        // QpsGauge name
         std::snprintf(buffer, sizeof(buffer),
                       "/stress_test/server_%d/channel_%d/stub_%d/qps",
                       server_idx, channel_idx, stub_idx);
 
         test_threads.emplace_back(grpc::thread(
             &StressTestInteropClient::MainLoop, client,
-            metrics_service.CreateGauge(buffer, &is_already_created)));
+            metrics_service.CreateQpsGauge(buffer, &is_already_created)));
 
-        // The Gauge should not have been already created
+        // The QpsGauge should not have been already created
         GPR_ASSERT(!is_already_created);
       }
     }
diff --git a/test/cpp/util/metrics_server.cc b/test/cpp/util/metrics_server.cc
index d9b44a6..cc6b39b 100644
--- a/test/cpp/util/metrics_server.cc
+++ b/test/cpp/util/metrics_server.cc
@@ -42,16 +42,26 @@
 namespace grpc {
 namespace testing {
 
-Gauge::Gauge(long initial_val) : val_(initial_val) {}
+QpsGauge::QpsGauge()
+    : start_time_(gpr_now(GPR_CLOCK_REALTIME)), num_queries_(0) {}
 
-void Gauge::Set(long new_val) {
-  std::lock_guard<std::mutex> lock(val_mu_);
-  val_ = new_val;
+void QpsGauge::Reset() {
+  std::lock_guard<std::mutex> lock(num_queries_mu_);
+  num_queries_ = 0;
+  start_time_ = gpr_now(GPR_CLOCK_REALTIME);
 }
 
-long Gauge::Get() {
-  std::lock_guard<std::mutex> lock(val_mu_);
-  return val_;
+void QpsGauge::Incr() {
+  std::lock_guard<std::mutex> lock(num_queries_mu_);
+  num_queries_++;
+}
+
+long QpsGauge::Get() {
+  std::lock_guard<std::mutex> lock(num_queries_mu_);
+  gpr_timespec time_diff =
+      gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start_time_);
+  long duration_secs = time_diff.tv_sec > 0 ? time_diff.tv_sec : 1;
+  return num_queries_ / duration_secs;
 }
 
 grpc::Status MetricsServiceImpl::GetAllGauges(
@@ -60,7 +70,7 @@
   gpr_log(GPR_DEBUG, "GetAllGauges called");
 
   std::lock_guard<std::mutex> lock(mu_);
-  for (auto it = gauges_.begin(); it != gauges_.end(); it++) {
+  for (auto it = qps_gauges_.begin(); it != qps_gauges_.end(); it++) {
     GaugeResponse resp;
     resp.set_name(it->first);                // Gauge name
     resp.set_long_value(it->second->Get());  // Gauge value
@@ -75,8 +85,8 @@
                                           GaugeResponse* response) {
   std::lock_guard<std::mutex> lock(mu_);
 
-  const auto it = gauges_.find(request->name());
-  if (it != gauges_.end()) {
+  const auto it = qps_gauges_.find(request->name());
+  if (it != qps_gauges_.end()) {
     response->set_name(it->first);
     response->set_long_value(it->second->Get());
   }
@@ -84,16 +94,17 @@
   return Status::OK;
 }
 
-std::shared_ptr<Gauge> MetricsServiceImpl::CreateGauge(const grpc::string& name,
-                                                       bool* already_present) {
+std::shared_ptr<QpsGauge> MetricsServiceImpl::CreateQpsGauge(
+    const grpc::string& name, bool* already_present) {
   std::lock_guard<std::mutex> lock(mu_);
 
-  std::shared_ptr<Gauge> gauge(new Gauge(0));
-  const auto p = gauges_.emplace(name, gauge);
+  std::shared_ptr<QpsGauge> qps_gauge(new QpsGauge());
+  const auto p = qps_gauges_.emplace(name, qps_gauge);
 
-  // p.first is an iterator pointing to <name, shared_ptr<Gauge>> pair. p.second
-  // is a boolean which is set to 'true' if the Gauge is inserted in the guages_
-  // map and 'false' if it is already present in the map
+  // p.first is an iterator pointing to <name, shared_ptr<QpsGauge>> pair.
+  // p.second is a boolean which is set to 'true' if the QpsGauge is
+  // successfully inserted in the guages_ map and 'false' if it is already
+  // present in the map
   *already_present = !p.second;
   return p.first->second;
 }
diff --git a/test/cpp/util/metrics_server.h b/test/cpp/util/metrics_server.h
index ce05e0b..aa9bfed 100644
--- a/test/cpp/util/metrics_server.h
+++ b/test/cpp/util/metrics_server.h
@@ -48,10 +48,13 @@
  * Example:
  *    MetricsServiceImpl metricsImpl;
  *    ..
- *    // Create Gauge(s). Note: Gauges can be created even after calling
+ *    // Create QpsGauge(s). Note: QpsGauges can be created even after calling
  *    // 'StartServer'.
- *    Gauge gauge1 = metricsImpl.CreateGauge("foo",is_present);
- *    // gauge1 can now be used anywhere in the program to set values.
+ *    QpsGauge qps_gauge1 = metricsImpl.CreateQpsGauge("foo", is_present);
+ *    // qps_gauge1 can now be used anywhere in the program by first making a
+ *    // one-time call qps_gauge1.Reset() and then calling qps_gauge1.Incr()
+ *    // every time to increment a query counter
+ *
  *    ...
  *    // Create the metrics server
  *    std::unique_ptr<grpc::Server> server = metricsImpl.StartServer(port);
@@ -60,17 +63,24 @@
 namespace grpc {
 namespace testing {
 
-// TODO(sreek): Add support for other types of Gauges like Double, String in
-// future
-class Gauge {
+class QpsGauge {
  public:
-  Gauge(long initial_val);
-  void Set(long new_val);
+  QpsGauge();
+
+  // Initialize the internal timer and reset the query count to 0
+  void Reset();
+
+  // Increment the query count by 1
+  void Incr();
+
+  // Return the current qps (i.e query count divided by the time since this
+  // QpsGauge object created (or Reset() was called))
   long Get();
 
  private:
-  long val_;
-  std::mutex val_mu_;
+  gpr_timespec start_time_;
+  long num_queries_;
+  std::mutex num_queries_mu_;
 };
 
 class MetricsServiceImpl GRPC_FINAL : public MetricsService::Service {
@@ -81,17 +91,17 @@
   grpc::Status GetGauge(ServerContext* context, const GaugeRequest* request,
                         GaugeResponse* response) GRPC_OVERRIDE;
 
-  // Create a Gauge with name 'name'. is_present is set to true if the Gauge
+  // Create a QpsGauge with name 'name'. is_present is set to true if the Gauge
   // is already present in the map.
-  // NOTE: CreateGauge can be called anytime (i.e before or after calling
+  // NOTE: CreateQpsGauge can be called anytime (i.e before or after calling
   // StartServer).
-  std::shared_ptr<Gauge> CreateGauge(const grpc::string& name,
-                                     bool* already_present);
+  std::shared_ptr<QpsGauge> CreateQpsGauge(const grpc::string& name,
+                                           bool* already_present);
 
   std::unique_ptr<grpc::Server> StartServer(int port);
 
  private:
-  std::map<string, std::shared_ptr<Gauge>> gauges_;
+  std::map<string, std::shared_ptr<QpsGauge>> qps_gauges_;
   std::mutex mu_;
 };
 
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
index dd77f7a..c6cc562 100755
--- a/tools/buildgen/plugins/expand_version.py
+++ b/tools/buildgen/plugins/expand_version.py
@@ -27,10 +27,10 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Buildgen .proto files list plugin.
+"""Buildgen package version plugin
 
 This parses the list of targets from the yaml build file, and creates
-a list called "protos" that contains all of the proto file names.
+a custom version string for each language's package.
 
 """
 
diff --git a/tools/dockerfile/grpc_base/Dockerfile b/tools/dockerfile/grpc_base/Dockerfile
deleted file mode 100644
index 9186277..0000000
--- a/tools/dockerfile/grpc_base/Dockerfile
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Base Dockerfile for gRPC dev images
-FROM debian:latest
-
-# Install Git.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  curl \
-  gcc \
-  git \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  strace \
-  python-dev \
-  python-setuptools \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-# Install useful useful python modules
-RUN easy_install -U pip
-RUN pip install -U crcmod  # makes downloads from cloud storage faster
-
-# Install GCloud
-RUN wget https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip \
-  && unzip google-cloud-sdk.zip && rm google-cloud-sdk.zip
-ENV CLOUD_SDK /google-cloud-sdk
-RUN $CLOUD_SDK/install.sh --usage-reporting=true --path-update=true --bash-completion=true --rc-path=/.bashrc --disable-installation-options
-ENV PATH $CLOUD_SDK/bin:$PATH
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/dockerfile/grpc_base/README.md b/tools/dockerfile/grpc_base/README.md
deleted file mode 100644
index 5c81b02..0000000
--- a/tools/dockerfile/grpc_base/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Base GRPC Dockerfile
-====================
-
-Dockerfile for creating the base gRPC development Docker instance.
-For now, this assumes that the development will be done on GCE instances,
-with source code on GitHub.
-
-As of 2015/02/02, it includes
-- git
-- some useful tools like curl, emacs, strace, telnet etc
-- a patched version of protoc, to allow protos with stream tags to work
diff --git a/tools/dockerfile/grpc_linuxbrew/Dockerfile b/tools/dockerfile/grpc_linuxbrew/Dockerfile
deleted file mode 100644
index 848489e..0000000
--- a/tools/dockerfile/grpc_linuxbrew/Dockerfile
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# A work-in-progress Dockerfile that allows running gRPC homebrew
-# installations inside docker containers
-FROM debian:jessie
-
-# Core dependencies
-RUN apt-get update && apt-get install -y \
-  bzip2 curl git ruby wget
-
-# Install linuxbrew
-ENV PATH /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
-RUN git clone https://github.com/Homebrew/linuxbrew.git /home/linuxbrew/.linuxbrew
-RUN brew doctor || true
-
-# Python dependency
-RUN apt-get update && apt-get install -y python-dev
-RUN curl https://bootstrap.pypa.io/get-pip.py | python
-
-# NodeJS dependency
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12"
-
-# Ruby dependency
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN /bin/bash -l -c "\curl -sSL https://get.rvm.io | bash -s stable"
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-
-# PHP dependency
-RUN apt-get update && apt-get install -y php5 php5-dev php-pear phpunit unzip
-
-RUN /bin/bash -l -c "echo 'export PATH=/home/linuxbrew/.linuxbrew/bin:\$PATH' >> ~/.bashrc"
-
-CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
similarity index 89%
rename from tools/dockerfile/grpc_interop_csharp/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index 93cd250..baab2f5 100644
--- a/tools/dockerfile/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -27,12 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,13 +40,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -59,15 +59,11 @@
   wget \
   zip && apt-get clean
 
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
 
-#################
+#================
 # C# dependencies
 
 # Update to a newer version of mono
@@ -84,5 +80,20 @@
     nuget \
     && apt-get clean
 
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_csharp/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_csharp/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_csharp/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
similarity index 85%
rename from tools/dockerfile/grpc_interop_cxx/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
index 1fa1907..2bbccca 100644
--- a/tools/dockerfile/grpc_interop_cxx/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
@@ -27,12 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,13 +40,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -59,6 +59,14 @@
   wget \
   zip && apt-get clean
 
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
@@ -67,9 +75,12 @@
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
 
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_cxx/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_cxx/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_cxx/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
similarity index 100%
rename from tools/dockerfile/grpc_interop_go/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
diff --git a/tools/dockerfile/grpc_interop_go/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_go/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_go/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_http2/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
similarity index 100%
rename from tools/dockerfile/grpc_interop_http2/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
diff --git a/tools/dockerfile/grpc_interop_http2/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_http2/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_http2/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_java/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
similarity index 92%
rename from tools/dockerfile/grpc_interop_java/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
index 370657b..252c9bc 100644
--- a/tools/dockerfile/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
@@ -31,23 +31,23 @@
 
 # Install JDK 8 and Git
 #
-# TODO(temiola): simplify this if/when a simpler process is available.
-#
 RUN echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections && \
   echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list && \
   echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list && \
-  apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886 && \
-  apt-get update && \
-  apt-get -y install \
+  apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
+
+RUN apt-get update && apt-get -y install \
       git \
       libapr1 \
       oracle-java8-installer \
       && \
-  apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
+    apt-get clean && rm -r /var/cache/oracle-jdk8-installer/
 
 ENV JAVA_HOME /usr/lib/jvm/java-8-oracle
 ENV PATH $PATH:$JAVA_HOME/bin
 
+
+
 # Trigger download of as many Gradle artifacts as possible.
 RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && \
   cd grpc-java && \
diff --git a/tools/dockerfile/grpc_interop_java/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_java/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_java/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
similarity index 84%
rename from tools/dockerfile/grpc_interop_node/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index db5aff8..64314f8 100644
--- a/tools/dockerfile/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -27,12 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,14 +40,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
-  libssl-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -60,6 +59,18 @@
   wget \
   zip && apt-get clean
 
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
@@ -68,13 +79,12 @@
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
 
-##################
-# Node dependencies
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12"
+RUN mkdir /var/local/jenkins
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_node/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
similarity index 98%
rename from tools/dockerfile/grpc_interop_node/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
index 4d4290d..b99fd44 100755
--- a/tools/dockerfile/grpc_interop_node/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_node/build_interop.sh
@@ -41,8 +41,6 @@
 nvm use 0.12
 nvm alias default 0.12  # prevent the need to run 'nvm use' in every shell
 
-make install-certs
-
 # build Node interop client & server
 npm install -g node-gyp
 npm install --unsafe-perm --build-from-source
diff --git a/tools/dockerfile/grpc_interop_php/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
similarity index 85%
rename from tools/dockerfile/grpc_interop_php/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
index cf3e791..e27a6a2 100644
--- a/tools/dockerfile/grpc_interop_php/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_php/Dockerfile
@@ -27,12 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,13 +40,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -59,15 +59,11 @@
   wget \
   zip && apt-get clean
 
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
 
-##################
+#==================
 # Ruby dependencies
 
 # Install rvm
@@ -82,14 +78,35 @@
 RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
 
-##################
+#=================
 # PHP dependencies
 
 # Install dependencies
 
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
 RUN apt-get update && apt-get install -y \
     git php5 php5-dev phpunit unzip
 
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
 # ronn: a ruby tool used to convert markdown to man pages, used during the
 # install of Protobuf extensions
 #
diff --git a/tools/dockerfile/grpc_interop_php/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_php/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_php/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_python/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
similarity index 77%
rename from tools/dockerfile/grpc_interop_python/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index 047604b..071fb2c 100644
--- a/tools/dockerfile/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -27,12 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,17 +40,18 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
-  libssl-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
-  python-pip \
   python-setuptools \
   python-yaml \
   telnet \
@@ -61,6 +59,25 @@
   wget \
   zip && apt-get clean
 
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
@@ -69,14 +86,12 @@
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang
 RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
 
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
-#####################
-# Python dependencies
-
-# Install Python requisites
-RUN /bin/bash -l -c "pip install --upgrade pip"
-RUN /bin/bash -l -c "pip install virtualenv"
-RUN /bin/bash -l -c "pip install tox"
+RUN mkdir /var/local/jenkins
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_python/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
similarity index 100%
rename from tools/dockerfile/grpc_interop_python/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_python/build_interop.sh
diff --git a/tools/dockerfile/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
similarity index 88%
rename from tools/dockerfile/grpc_interop_ruby/Dockerfile
rename to tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
index ff201fa..df8eef5 100644
--- a/tools/dockerfile/grpc_interop_ruby/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
@@ -27,12 +27,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
 FROM debian:jessie
 
-# Install Git.
+# Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
   autoconf \
   autotools-dev \
@@ -43,13 +40,16 @@
   gcc \
   gcc-multilib \
   git \
+  golang \
   gyp \
+  lcov \
   libc6 \
   libc6-dbg \
   libc6-dev \
   libgtest-dev \
   libtool \
   make \
+  perl \
   strace \
   python-dev \
   python-setuptools \
@@ -59,16 +59,11 @@
   wget \
   zip && apt-get clean
 
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
 
-
-##################
+#==================
 # Ruby dependencies
 
 # Install rvm
@@ -83,5 +78,20 @@
 RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
 RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
 
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/grpc_interop_ruby/build_interop.sh b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
similarity index 98%
rename from tools/dockerfile/grpc_interop_ruby/build_interop.sh
rename to tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
index 685397b..97b3860 100755
--- a/tools/dockerfile/grpc_interop_ruby/build_interop.sh
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/build_interop.sh
@@ -40,7 +40,5 @@
 cd /var/local/git/grpc
 rvm --default use ruby-2.1
 
-make install-certs
-
 # build Ruby interop client and server
 (cd src/ruby && gem update bundler && bundle && rake compile)
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 478e04e..25ac3bc 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -83,11 +83,13 @@
 # Python dependencies
 sudo pip install tabulate
 sudo pip install google-api-python-client
+sudo pip install tox
 
 curl -O https://bootstrap.pypa.io/get-pip.py
 sudo pypy get-pip.py
 sudo pypy -m pip install tabulate
 sudo pip install google-api-python-client
+sudo pip install tox
 
 # Node dependencies (nvm has to be installed under user jenkins)
 touch .profile
diff --git a/tools/jenkins/build_interop_image.sh b/tools/jenkins/build_interop_image.sh
index 26687a5..d2ba97c 100755
--- a/tools/jenkins/build_interop_image.sh
+++ b/tools/jenkins/build_interop_image.sh
@@ -71,10 +71,10 @@
 fi
 
 # Use image name based on Dockerfile checksum
-BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/dockerfile/$BASE_NAME/Dockerfile | cut -f1 -d\ `
+BASE_IMAGE=${BASE_NAME}_base:`sha1sum tools/dockerfile/interoptest/$BASE_NAME/Dockerfile | cut -f1 -d\ `
 
 # Make sure base docker image has been built. Should be instantaneous if so.
-docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/$BASE_NAME || exit $?
+docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/interoptest/$BASE_NAME || exit $?
 
 # Create a local branch so the child Docker script won't complain
 git branch -f jenkins-docker
@@ -92,7 +92,7 @@
   -v /tmp/ccache:/tmp/ccache \
   --name=$CONTAINER_NAME \
   $BASE_IMAGE \
-  bash -l /var/local/jenkins/grpc/tools/dockerfile/$BASE_NAME/build_interop.sh \
+  bash -l /var/local/jenkins/grpc/tools/dockerfile/interoptest/$BASE_NAME/build_interop.sh \
   && docker commit $CONTAINER_NAME $INTEROP_IMAGE \
   && echo "Successfully built image $INTEROP_IMAGE")
 EXITCODE=$?
diff --git a/tools/jenkins/run_distribution.sh b/tools/jenkins/run_distribution.sh
deleted file mode 100755
index 306b85b..0000000
--- a/tools/jenkins/run_distribution.sh
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/bin/bash
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# This script is invoked by Jenkins and triggers a test run of
-# linuxbrew installation of a selected language
-set -ex
-
-# Our homebrew installation script command, per language
-# Can be used in both linux and macos
-if [ "$language" == "core" ]; then
-  command="curl -fsSL https://goo.gl/getgrpc | bash -"
-elif [[ "python nodejs ruby php" =~ "$language" ]]; then
-  command="curl -fsSL https://goo.gl/getgrpc | bash -s $language"
-else
-  echo "unsupported language $language"
-  exit 1
-fi
-
-if [ "$platform" == "linux" ]; then
-
-  if [ "$dist_channel" == "homebrew" ]; then
-
-    sha1=$(sha1sum tools/dockerfile/grpc_linuxbrew/Dockerfile | cut -f1 -d\ )
-    DOCKER_IMAGE_NAME=grpc_linuxbrew_$sha1
-
-    # build docker image, contains all pre-requisites
-    docker build -t $DOCKER_IMAGE_NAME tools/dockerfile/grpc_linuxbrew
-
-    # run per-language homebrew installation script
-    docker run --rm=true $DOCKER_IMAGE_NAME bash -l \
-      -c "nvm use 0.12; \
-          npm set unsafe-perm true; \
-          rvm use ruby-2.1; \
-          $command"
-
-  else
-    echo "Unsupported $platform dist_channel $dist_channel"
-    exit 1
-  fi
-
-elif [ "$platform" == "macos" ]; then
-
-  if [ "$dist_channel" == "homebrew" ]; then
-
-    echo "Formulas installed by system-wide homebrew (before)"
-    brew list -l
-
-    # Save the original PATH so that we can run the system `brew` command
-    # again at the end of the script
-    export ORIGINAL_PATH=$PATH
-
-    # Set up temp directories for test installation of homebrew
-    brew_root=/tmp/homebrew-test-$language
-    rm -rf $brew_root
-    mkdir -p $brew_root
-    git clone https://github.com/Homebrew/homebrew.git $brew_root
-
-    # Make sure we are operating at the right copy of temp homebrew
-    # installation
-    export PATH=$brew_root/bin:$PATH
-
-    # Set up right environment for each language
-    case $language in
-      *python*)
-        rm -rf jenkins_python_venv
-        virtualenv jenkins_python_venv
-        source jenkins_python_venv/bin/activate
-        ;;
-      *nodejs*)
-        export PATH=$HOME/.nvm/versions/node/v0.12.7/bin:$PATH
-        ;;
-      *ruby*)
-        export PATH=/usr/local/rvm/rubies/ruby-2.2.1/bin:$PATH
-        ;;
-      *php*)
-        export CFLAGS="-Wno-parentheses-equality"
-        ;;
-    esac
-
-    # Run our homebrew installation script
-    bash -c "$command"
-
-    # Uninstall / clean up per-language modules/extensions after the test
-    case $language in
-      *python*)
-        deactivate
-        rm -rf jenkins_python_venv
-        ;;
-      *nodejs*)
-        npm list -g | grep grpc
-        npm uninstall -g grpc
-        ;;
-      *ruby*)
-        gem list | grep grpc
-        gem uninstall grpc
-        ;;
-      *php*)
-        rm grpc.so
-        ;;
-    esac
-
-    # Clean up
-    rm -rf $brew_root
-
-    echo "Formulas installed by system-wide homebrew (after, should be unaffected)"
-    export PATH=$ORIGINAL_PATH
-    brew list -l
-
-  else
-    echo "Unsupported $platform dist_channel $dist_channel"
-    exit 1
-  fi
-
-else
-  echo "unsupported platform $platform"
-  exit 1
-fi
diff --git a/tools/jenkins/run_performance.sh b/tools/jenkins/run_performance.sh
index 903a144..13a3327 100755
--- a/tools/jenkins/run_performance.sh
+++ b/tools/jenkins/run_performance.sh
@@ -34,4 +34,4 @@
 # Enter the gRPC repo root
 cd $(dirname $0)/../..
 
-tools/run_tests/run_performance_tests.py -l c++ node ruby csharp
+tools/run_tests/run_performance_tests.py -l c++ node ruby csharp python
diff --git a/tools/run_tests/build_package_node.sh b/tools/run_tests/build_package_node.sh
index 540c826..6bc9466 100755
--- a/tools/run_tests/build_package_node.sh
+++ b/tools/run_tests/build_package_node.sh
@@ -35,10 +35,54 @@
 
 cd $(dirname $0)/../..
 
-mkdir -p artifacts/
-cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=node,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+base=$(pwd)
+
+artifacts=$base/artifacts
+
+mkdir -p $artifacts
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=node,platform={windows,linux,macos}/artifacts/* $artifacts/ || true
 
 npm update
 npm pack
 
-cp grpc-*.tgz artifacts/grpc.tgz
+cp grpc-*.tgz $artifacts/grpc.tgz
+
+mkdir -p bin
+
+cd src/node/tools
+npm update
+npm pack
+cp grpc-tools-*.tgz $artifacts/
+tools_version=$(npm list | grep -oP '(?<=grpc-tools@)\S+')
+
+output_dir=$artifacts/grpc-precompiled-binaries/node/grpc-tools/$tools_version
+mkdir -p $output_dir
+
+for arch in {x86,x64}; do
+  case arch in
+    x86)
+      node_arch=ia32
+      ;;
+    *)
+      node_arch=$arch
+      ;;
+  esac
+  for plat in {windows,linux,macos}; do
+    case plat in
+      windows)
+        node_plat=win32
+        ;;
+      macos)
+        node_plat=darwin
+        ;;
+      *)
+        node_plat=$plat
+        ;;
+    esac
+    rm bin/*
+    input_dir="$EXTERNAL_GIT_ROOT/architecture=$arch,language=protoc,platform=$plat/artifacts"
+    cp $input_dir/protoc* bin/
+    cp $input_dir/grpc_node_plugin* bin/
+    tar -czf $output_dir/$node_plat-$node_arch.tar.gz bin/
+  done
+done
diff --git a/tools/dockerfile/grpc_interop_node/build_interop.sh b/tools/run_tests/performance/kill_workers.sh
similarity index 74%
copy from tools/dockerfile/grpc_interop_node/build_interop.sh
copy to tools/run_tests/performance/kill_workers.sh
index 4d4290d..3eae8c3 100755
--- a/tools/dockerfile/grpc_interop_node/build_interop.sh
+++ b/tools/run_tests/performance/kill_workers.sh
@@ -27,22 +27,25 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Builds Node interop server and client in a base image.
-set -e
 
-mkdir -p /var/local/git
-git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
+set -ex
 
-# copy service account keys if available
-cp -r /var/local/jenkins/service_account $HOME || true
+cd $(dirname $0)/../../..
 
-cd /var/local/git/grpc
-nvm use 0.12
-nvm alias default 0.12  # prevent the need to run 'nvm use' in every shell
+# Make sure there are no pre-existing QPS workers around before starting
+# the performance test suite
 
-make install-certs
+# C++
+killall -9 qps_worker || true
 
-# build Node interop client & server
-npm install -g node-gyp
-npm install --unsafe-perm --build-from-source
+# C#
+ps -C mono -o pid=,cmd= | grep QpsWorker | awk '{print $1}' | xargs kill -9
+
+# Ruby
+ps -C ruby -o pid=,cmd= | grep 'qps/worker.rb' | awk '{print $1}' | xargs kill -9
+
+# Node
+ps -C node -o pid=,cmd= | grep 'performance/worker.js' | awk '{print $1}' | xargs kill -9
+
+# Java
+jps | grep LoadWorker | awk '{print $1}' | xargs kill -9
diff --git a/tools/run_tests/performance/remote_host_prepare.sh b/tools/run_tests/performance/remote_host_prepare.sh
index 17cfa1a..d7f539a 100755
--- a/tools/run_tests/performance/remote_host_prepare.sh
+++ b/tools/run_tests/performance/remote_host_prepare.sh
@@ -41,10 +41,9 @@
 # could also kill jenkins.
 ssh "${USER_AT_HOST}" "killall -9 qps_worker mono node ruby || true"
 
-# Kill all java LoadWorker processes. We can't just killall java
-# as one of the processes might be jenkins.
-ssh "${USER_AT_HOST}" 'kill -9 $(jps | grep LoadWorker | cut -f1 -d" ") || true'
-
 # push the current sources to the slave and unpack it.
 scp ../grpc.tar "${USER_AT_HOST}:~/performance_workspace"
 ssh "${USER_AT_HOST}" "tar -xf ~/performance_workspace/grpc.tar -C ~/performance_workspace"
+
+# For consistency with local run, invoke the kill_workers script remotely.
+ssh "${USER_AT_HOST}" "~/performance_workspace/grpc/tools/run_tests/performance/kill_workers.sh"
diff --git a/src/python/grpcio/tests/unit/framework/face/__init__.py b/tools/run_tests/performance/run_worker_python.sh
old mode 100644
new mode 100755
similarity index 87%
copy from src/python/grpcio/tests/unit/framework/face/__init__.py
copy to tools/run_tests/performance/run_worker_python.sh
index 7086519..0da8ded
--- a/src/python/grpcio/tests/unit/framework/face/__init__.py
+++ b/tools/run_tests/performance/run_worker_python.sh
@@ -1,4 +1,5 @@
-# Copyright 2015, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -27,4 +28,8 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+set -ex
 
+cd $(dirname $0)/../../..
+
+PYTHONPATH=src/python/grpcio:src/python/gens .tox/py27/bin/python src/python/grpcio/tests/qps/qps_worker.py $@
diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py
index 55657f8..ddbe237 100644
--- a/tools/run_tests/performance/scenario_config.py
+++ b/tools/run_tests/performance/scenario_config.py
@@ -456,6 +456,128 @@
   def __str__(self):
     return 'node'
 
+class PythonLanguage:
+
+  def __init__(self):
+    self.safename = 'python'
+
+  def worker_cmdline(self):
+    return ['tools/run_tests/performance/run_worker_python.sh']
+
+  def worker_port_offset(self):
+    return 500
+
+  def scenarios(self):
+    yield {
+        'name': 'python_to_cpp_protobuf_streaming_ping_pong',
+        'num_servers': 1,
+        'num_clients': 1,
+        'client_config': {
+          'client_type': 'ASYNC_CLIENT',
+          'security_params': SECURE_SECARGS,
+          'outstanding_rpcs_per_channel': 1,
+          'client_channels': 1,
+          'async_client_threads': 1,
+          'rpc_type': 'STREAMING',
+          'load_params': {
+            'closed_loop': {}
+          },
+          'payload_config': EMPTY_PROTO_PAYLOAD,
+          'histogram_params': HISTOGRAM_PARAMS,
+        },
+        'server_config': {
+          'server_type': 'SYNC_SERVER',
+          'security_params': SECURE_SECARGS,
+          'core_limit': 0,
+          'async_server_threads': 1,
+        },
+        'warmup_seconds': WARMUP_SECONDS,
+        'benchmark_seconds': BENCHMARK_SECONDS,
+        'SERVER_LANGUAGE': 'c++' 
+    }
+    yield {
+        'name': 'python_protobuf_sync_unary_ping_pong',
+        'num_servers': 1,
+        'num_clients': 1,
+        'client_config': {
+          'client_type': 'SYNC_CLIENT',
+          'security_params': SECURE_SECARGS,
+          'outstanding_rpcs_per_channel': 1,
+          'client_channels': 1,
+          'async_client_threads': 1,
+          'rpc_type': 'UNARY',
+          'load_params': {
+            'closed_loop': {}
+          },
+          'payload_config': EMPTY_PROTO_PAYLOAD,
+          'histogram_params': HISTOGRAM_PARAMS,
+        },
+        'server_config': {
+          'server_type': 'SYNC_SERVER',
+          'security_params': SECURE_SECARGS,
+          'core_limit': 0,
+          'async_server_threads': 1,
+        },
+        'warmup_seconds': WARMUP_SECONDS,
+        'benchmark_seconds': BENCHMARK_SECONDS,
+    }
+    yield {
+        'name': 'python_protobuf_async_unary_ping_pong',
+        'num_servers': 1,
+        'num_clients': 1,
+        'client_config': {
+          'client_type': 'ASYNC_CLIENT',
+          'security_params': SECURE_SECARGS,
+          'outstanding_rpcs_per_channel': 1,
+          'client_channels': 1,
+          'async_client_threads': 1,
+            'rpc_type': 'UNARY',
+            'load_params': {
+              'closed_loop': {}
+            },
+            'payload_config': EMPTY_PROTO_PAYLOAD,
+            'histogram_params': HISTOGRAM_PARAMS,
+          },
+          'server_config': {
+            'server_type': 'SYNC_SERVER',
+            'security_params': SECURE_SECARGS,
+            'core_limit': 0,
+            'async_server_threads': 1,
+          },
+          'warmup_seconds': WARMUP_SECONDS,
+          'benchmark_seconds': BENCHMARK_SECONDS,
+    }
+    yield {
+        'name': 'python_to_cpp_single_channel_throughput',
+        'num_servers': 1,
+        'num_clients': 1,
+        'client_config': {
+          'client_type': 'ASYNC_CLIENT',
+          'security_params': SECURE_SECARGS,
+          'outstanding_rpcs_per_channel': 1,
+          'client_channels': 1,
+          'async_client_threads': 1,
+          'rpc_type': 'STREAMING',
+          'load_params': {
+            'closed_loop': {}
+          },
+          'payload_config': BIG_GENERIC_PAYLOAD,
+          'histogram_params': HISTOGRAM_PARAMS,
+        },
+        'server_config': {
+          'server_type': 'ASYNC_GENERIC_SERVER',
+          'security_params': SECURE_SECARGS,
+          'core_limit': SINGLE_MACHINE_CORES/2,
+          'async_server_threads': 1,
+          'payload_config': BIG_GENERIC_PAYLOAD,
+        },
+        'warmup_seconds': WARMUP_SECONDS,
+        'benchmark_seconds': BENCHMARK_SECONDS,
+        'SERVER_LANGUAGE': 'c++'
+    }
+      
+  def __str__(self):
+    return 'python'
 
 class RubyLanguage:
 
@@ -562,4 +684,5 @@
     'node' : NodeLanguage(),
     'ruby' : RubyLanguage(),
     'java' : JavaLanguage(),
+    'python' : PythonLanguage(),
 }
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 18d4c10..758be93 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -111,8 +111,7 @@
     return {}
 
   def unimplemented_test_cases(self):
-    # TODO: status_code_and_message doesn't work against node_server
-    return _SKIP_COMPRESSION + ['status_code_and_message']
+    return _SKIP_COMPRESSION
 
   def unimplemented_test_cases_server(self):
     return _SKIP_COMPRESSION
diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py
index ada341a..5519666 100755
--- a/tools/run_tests/run_performance_tests.py
+++ b/tools/run_tests/run_performance_tests.py
@@ -157,8 +157,9 @@
     sys.exit(1)
 
 
-def prepare_remote_hosts(hosts):
-  """Prepares remote hosts."""
+def prepare_remote_hosts(hosts, prepare_local=False):
+  """Prepares remote hosts (and maybe prepare localhost as well)."""
+  prepare_timeout = 5*60
   prepare_jobs = []
   for host in hosts:
     user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, host)
@@ -167,13 +168,20 @@
             cmdline=['tools/run_tests/performance/remote_host_prepare.sh'],
             shortname='remote_host_prepare.%s' % host,
             environ = {'USER_AT_HOST': user_at_host},
-            timeout_seconds=5*60))
-  jobset.message('START', 'Preparing remote hosts.', do_newline=True)
+            timeout_seconds=prepare_timeout))
+  if prepare_local:
+    # Prepare localhost as well
+    prepare_jobs.append(
+        jobset.JobSpec(
+            cmdline=['tools/run_tests/performance/kill_workers.sh'],
+            shortname='local_prepare',
+            timeout_seconds=prepare_timeout))
+  jobset.message('START', 'Preparing hosts.', do_newline=True)
   num_failures, _ = jobset.run(
       prepare_jobs, newline_on_success=True, maxjobs=10)
   if num_failures == 0:
     jobset.message('SUCCESS',
-                   'Remote hosts ready to start build.',
+                   'Prepare step completed successfully.',
                    do_newline=True)
   else:
     jobset.message('FAILED', 'Failed to prepare remote hosts.',
@@ -238,6 +246,9 @@
 def create_scenarios(languages, workers_by_lang, remote_host=None, regex='.*',
                      bq_result_table=None):
   """Create jobspecs for scenarios to run."""
+  all_workers = [worker
+                 for workers in workers_by_lang.values()
+                 for worker in workers]
   scenarios = []
   for language in languages:
     for scenario_json in language.scenarios():
@@ -263,9 +274,6 @@
         scenarios.append(scenario)
 
   # the very last scenario requests shutting down the workers.
-  all_workers = [worker
-                 for workers in workers_by_lang.values()
-                 for worker in workers]
   scenarios.append(create_quit_jobspec(all_workers, remote_host=remote_host))
   return scenarios
 
@@ -322,7 +330,9 @@
 
 if remote_hosts:
   archive_repo(languages=[str(l) for l in languages])
-  prepare_remote_hosts(remote_hosts)
+  prepare_remote_hosts(remote_hosts, prepare_local=True)
+else:
+  prepare_remote_hosts([], prepare_local=True)
 
 build_local = False
 if not args.remote_driver_host:
diff --git a/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md b/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
index 62ca8af..9f079be 100644
--- a/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
+++ b/tools/run_tests/stress_test/STRESS_CLIENT_SPEC.md
@@ -6,8 +6,8 @@
 --------------

 **1.** A stress test client should be able to repeatedly execute one or more of the existing 'interop test cases'. It may just be a wrapper around the existing interop test client. The exact command line arguments the client should support are listed in _Table 1_ below.

 

-**2.** The stress test client must implement a metrics server defined by _[metrics.proto](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/metrics.proto)_ and must expose _qps_ as a long-valued Gauge. The client can track the overall _qps_ in one Gauge or in multiple Gauges (for example: One per Channel or Stub).

- The framework periodically queries the _qps_ by calling the `GetAllGauges()` method (the framework assumes that all the returned Gauges are _qps_ Gauges) and uses this to determine if the stress test client is running or crashed or stalled.

+**2.** The stress test client must implement a metrics server defined by _[metrics.proto](https://github.com/grpc/grpc/blob/master/src/proto/grpc/testing/metrics.proto)_ and must expose _qps_ as a `Long`-valued Gauge. The client can track the overall _qps_ in one Gauge or in multiple Gauges (for example: One per Channel or Stub).

+ The framework periodically queries the _qps_ by calling the `GetAllGauges()` method (the framework assumes that all the returned Gauges are _qps_ Gauges and adds them up to determine the final qps) and uses this to determine if the stress test client is running or crashed or stalled.

 > *Note:* In this context, the term  _**qps**_  means _interop test cases per second_  (not _messages per second_ or _rpc calls per second_)

 

 

diff --git a/tools/run_tests/stress_test/configs/asan.json b/tools/run_tests/stress_test/configs/asan.json
index c558855..cb9f557 100644
--- a/tools/run_tests/stress_test/configs/asan.json
+++ b/tools/run_tests/stress_test/configs/asan.json
@@ -16,8 +16,7 @@
           "num_channels_per_server":5,
           "num_stubs_per_channel":10,
           "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
-          "metrics_port": 8081,
-          "metrics_collection_interval_secs":120
+          "metrics_port": 8081
         },
         "metricsPort": 8081,
         "metricsArgs": {
diff --git a/tools/run_tests/stress_test/configs/opt-tsan-asan.json b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
index 4f172ef..936d151 100644
--- a/tools/run_tests/stress_test/configs/opt-tsan-asan.json
+++ b/tools/run_tests/stress_test/configs/opt-tsan-asan.json
@@ -26,8 +26,7 @@
           "num_channels_per_server":5,
           "num_stubs_per_channel":10,
           "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
-          "metrics_port": 8081,
-          "metrics_collection_interval_secs": 60
+          "metrics_port": 8081
         },
         "metricsPort": 8081,
         "metricsArgs": {
diff --git a/tools/run_tests/stress_test/configs/opt.json b/tools/run_tests/stress_test/configs/opt.json
index 7550518..f45b824 100644
--- a/tools/run_tests/stress_test/configs/opt.json
+++ b/tools/run_tests/stress_test/configs/opt.json
@@ -16,8 +16,7 @@
           "num_channels_per_server":5,
           "num_stubs_per_channel":10,
           "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
-          "metrics_port": 8081,
-          "metrics_collection_interval_secs": 60
+          "metrics_port": 8081
         },
         "metricsPort": 8081,
         "metricsArgs": {
diff --git a/tools/run_tests/stress_test/configs/tsan.json b/tools/run_tests/stress_test/configs/tsan.json
index a7ec083..6ef3bdf 100644
--- a/tools/run_tests/stress_test/configs/tsan.json
+++ b/tools/run_tests/stress_test/configs/tsan.json
@@ -16,8 +16,7 @@
           "num_channels_per_server":5,
           "num_stubs_per_channel":10,
           "test_cases": "empty_unary:1,large_unary:1,client_streaming:1,server_streaming:1,empty_stream:1",
-          "metrics_port": 8081,
-          "metrics_collection_interval_secs":120
+          "metrics_port": 8081
         },
         "metricsPort": 8081,
         "metricsArgs": {
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 245108a..0fd7785 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -23487,6 +23487,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/04a5f10d2ebc712cf13c05b5ed0fafb31b42737c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/04e01f399f194434b2b724877df64828e8f52c14"
     ], 
     "ci_platforms": [
@@ -25551,6 +25567,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/38a55e83e685617cdf72e95f1303857b627ae346"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/38c609f72f5a2cf977788afef9c34652f754add0"
     ], 
     "ci_platforms": [
@@ -25743,6 +25775,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/40b4b92460c4e76a39af9042fb3d86d491a98e16"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/42324d3d9e013cd43d4feeed1b48fbe1ea18a732"
     ], 
     "ci_platforms": [
@@ -26911,6 +26959,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/6914f5f380c83ff9e3e90fc60d5048e47e5e77d9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/696ea30e2e1490f2f31b153641b2c29152ded5c2"
     ], 
     "ci_platforms": [
@@ -27423,6 +27487,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/7abe8c414aa1418157c2d7ae5e70a84ffb61c027"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/7be89fb64b3d931387e8a5b1ef51bf9cda18006a"
     ], 
     "ci_platforms": [
@@ -28047,6 +28127,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/8c5bbcc6935d43c94a0c4ce4a5da01c04fd223d8"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/8d7bb385d6b13b0e689a1e81e29113746218ba99"
     ], 
     "ci_platforms": [
@@ -29375,6 +29471,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/b5bcc7f39420e997ec6f8e3c70ef49b8f1afb361"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/b5daec8e0821e8626c9b93ece56ccfef0511346b"
     ], 
     "ci_platforms": [
@@ -32671,6 +32783,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/api_fuzzer_corpus/f755b44ff2221c971ca2bfaffc69e002ba982730"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "api_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/api_fuzzer_corpus/f788d2b893fe39fe24582acffa6a70f1ca4e3037"
     ], 
     "ci_platforms": [
@@ -33983,6 +34111,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1e64080289ea4168304417f3fbd86b01d7d6f431"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/1e84d42fcf18bbf81ef6e8a16a0c57abbf8d292a"
     ], 
     "ci_platforms": [
@@ -34143,6 +34287,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/20ee437b7f456ebb19d98d94d9feb1d5e9174c65"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/2166c7093c424a2136c4cb8b10d0b124047320d4"
     ], 
     "ci_platforms": [
@@ -34527,6 +34687,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2c1ecf05c5dde692ed16502294e9570ac3b02600"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/2c342f8715556398d49bcf3343b5a249d968e19e"
     ], 
     "ci_platforms": [
@@ -37679,6 +37855,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/aa878edb0100e876e00e310ae221b220fdb5e028"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/aaada46c7f3bff58c2dd6f4a8394135ed5f253ee"
     ], 
     "ci_platforms": [
@@ -40127,6 +40319,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/slow-unit-53cf4d25741d5f6e7ad9147b286ff0b40cb500a9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/transport/chttp2/hpack_parser_corpus/0141fcddc9807ee093313b2256f1306fbbdc6cda"
     ], 
     "ci_platforms": [
@@ -57535,6 +57743,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/03a304b82629155af693978c2b53439e553f6450"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/03b9be1fa172dff5d1543be079b9c64fa2c9a278"
     ], 
     "ci_platforms": [
@@ -57551,6 +57775,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/052c8f28e5884bb48f0d504461272cd3a5893215"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/05c3a0390d0f52d241728926fa901599a47e4606"
     ], 
     "ci_platforms": [
@@ -58543,6 +58783,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/2c4c7e2ed6d977ec119b040b328ad09808909a70"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/2c6660ba.bin"
     ], 
     "ci_platforms": [
@@ -59311,6 +59567,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/4d982c41efad2242f8c06630c23c68146153b47b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/4db3d4075ed27f2a2311f85dd1d6df028cc5d083"
     ], 
     "ci_platforms": [
@@ -60399,6 +60671,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/830e3f794c53f7b284eb5c635b2943db9ee9aaee"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/8338ebee.bin"
     ], 
     "ci_platforms": [
@@ -62831,6 +63119,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-0aa52e00ddd54f8e129430852c2da95650c354b0"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-13501419f349b7855d2e94060bd08b28923d1f37"
     ], 
     "ci_platforms": [
@@ -62927,6 +63231,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-3cec540a680b108dda1e0a8e0bfb2d44e5a4a4e8"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-4c6da955e4c101b81a62b2f8e934d94a62ae534b"
     ], 
     "ci_platforms": [
@@ -63087,6 +63407,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-84f22ffca68c6e1590a44aa9f6dd0cef1f680c77"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-93cd6b3f9786ee107a0e2d135b40d13f96e652ed"
     ], 
     "ci_platforms": [
@@ -63167,6 +63503,70 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-adaac86cf1aa1e98e95240c5f92c3708456c3624"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-b281f018cc919301131cf3ed28449cfbd24b6bbf"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba0016a62a8576a57f000b90c364847ef6b12dcc"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba17346b8e46e6a05aaa7342a959a7c5ab0f1471"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ba2b1fde90cc70d9abae22c4c4cb051aae8aa148"
     ], 
     "ci_platforms": [
@@ -63247,6 +63647,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ccafab6afdc6474610023b47bd7b3e1b9ea4647b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-d3c3cba3897fafec97665411ea1f94a89bb4de7b"
     ], 
     "ci_platforms": [
@@ -63279,6 +63695,22 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-dc57e96cd02ba32fa4a99c97b6490e9879d30be5"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-ddfe613d8791b2d377e14fbdffb18b84a89d49b6"
     ], 
     "ci_platforms": [
@@ -63311,6 +63743,38 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f6c1042f96e15183dcc13b9658d971cc29426d53"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/slow-unit-f9a2773d6502fd4b1ffa73df3c550b0da63af833"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "test/core/client_config/uri_corpus/02d156dc5e6f2c11c90c2e06fcee04adf036a342"
     ], 
     "ci_platforms": [