Merge pull request #15130 from jiangtaoli2016/fake_handshaker

Add fake ALTS handshaker server (bazel only)
diff --git a/.pylintrc-tests b/.pylintrc-tests
index e68fd47..b358b2c 100644
--- a/.pylintrc-tests
+++ b/.pylintrc-tests
@@ -39,28 +39,16 @@
 	too-many-public-methods,
 	too-many-locals,
 	redefined-variable-type,
-	old-style-class,
 	redefined-outer-name,
-	bare-except,
-	broad-except,
 	ungrouped-imports,
 	too-many-branches,
 	too-many-arguments,
 	too-many-format-args,
 	too-many-return-statements,
 	too-many-statements,
-	undefined-variable,
-	function-redefined,
-	unnecessary-lambda,
-	wildcard-import,
 	line-too-long,
-	unreachable,
 	wrong-import-position,
 	wrong-import-order,
-	non-iterator-returned,
-	undefined-loop-variable,
-	raising-bad-type,
-	bad-continuation,
 	# -- END OF TEST-SPECIFIC SUPPRESSIONS --
 
 
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 88df3fb..43f5970 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5262,6 +5262,7 @@
   test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
   test/core/end2end/tests/retry_non_retriable_status.cc
+  test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   test/core/end2end/tests/retry_recv_initial_metadata.cc
   test/core/end2end/tests/retry_recv_message.cc
   test/core/end2end/tests/retry_server_pushback_delay.cc
@@ -5379,6 +5380,7 @@
   test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc
   test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc
   test/core/end2end/tests/retry_non_retriable_status.cc
+  test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
   test/core/end2end/tests/retry_recv_initial_metadata.cc
   test/core/end2end/tests/retry_recv_message.cc
   test/core/end2end/tests/retry_server_pushback_delay.cc
diff --git a/Makefile b/Makefile
index dce07b2..8aa53af 100644
--- a/Makefile
+++ b/Makefile
@@ -9910,6 +9910,7 @@
     test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc \
     test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc \
     test/core/end2end/tests/retry_non_retriable_status.cc \
+    test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc \
     test/core/end2end/tests/retry_recv_initial_metadata.cc \
     test/core/end2end/tests/retry_recv_message.cc \
     test/core/end2end/tests/retry_server_pushback_delay.cc \
@@ -10025,6 +10026,7 @@
     test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc \
     test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc \
     test/core/end2end/tests/retry_non_retriable_status.cc \
+    test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc \
     test/core/end2end/tests/retry_recv_initial_metadata.cc \
     test/core/end2end/tests/retry_recv_message.cc \
     test/core/end2end/tests/retry_server_pushback_delay.cc \
diff --git a/bazel/grpc_deps.bzl b/bazel/grpc_deps.bzl
index 00e313c..3c69a6b 100644
--- a/bazel/grpc_deps.bzl
+++ b/bazel/grpc_deps.bzl
@@ -85,8 +85,8 @@
     if "com_google_protobuf" not in native.existing_rules():
         native.http_archive(
             name = "com_google_protobuf",
-            strip_prefix = "protobuf-2761122b810fe8861004ae785cc3ab39f384d342",
-            url = "https://github.com/google/protobuf/archive/2761122b810fe8861004ae785cc3ab39f384d342.tar.gz",
+            strip_prefix = "protobuf-b5fbb742af122b565925987e65c08957739976a7",
+            url = "https://github.com/google/protobuf/archive/b5fbb742af122b565925987e65c08957739976a7.tar.gz",
         )
 
     if "com_github_google_googletest" not in native.existing_rules():
diff --git a/doc/environment_variables.md b/doc/environment_variables.md
index ed46a48..587ab83 100644
--- a/doc/environment_variables.md
+++ b/doc/environment_variables.md
@@ -50,6 +50,7 @@
   - channel_stack_builder - traces information about channel stacks being built
   - executor - traces grpc's internal thread pool ('the executor')
   - glb - traces the grpclb load balancer
+  - handshaker - traces handshaking state
   - http - traces state in the http2 transport engine
   - http2_stream_state - traces all http2 stream state mutations.
   - http1 - traces HTTP/1.x operations performed by gRPC
diff --git a/etc/roots.pem b/etc/roots.pem
index 15d819b..5dbd1ae 100644
--- a/etc/roots.pem
+++ b/etc/roots.pem
@@ -3525,39 +3525,6 @@
 5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
 -----END CERTIFICATE-----
 
-# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
-# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5 O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
-# Label: "TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5"
-# Serial: 156233699172481
-# MD5 Fingerprint: da:70:8e:f0:22:df:93:26:f6:5f:9f:d3:15:06:52:4e
-# SHA1 Fingerprint: c4:18:f6:4d:46:d1:df:00:3d:27:30:13:72:43:a9:12:11:c6:75:fb
-# SHA256 Fingerprint: 49:35:1b:90:34:44:c1:85:cc:dc:5c:69:3d:24:d8:55:5c:b2:08:d6:a8:14:13:07:69:9f:4a:f0:63:19:9d:78
------BEGIN CERTIFICATE-----
-MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UE
-BhMCVFIxDzANBgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxn
-aSDEsGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkg
-QS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1QgRWxla3Ryb25payBTZXJ0aWZpa2Eg
-SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAwODA3MDFaFw0yMzA0
-MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYD
-VQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8
-dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApCUZ4WWe60ghUEoI5RHwWrom
-/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537jVJp45wnEFPzpALFp/kR
-Gml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1mep5Fimh3
-4khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z
-5UNP9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0
-hO8EuPbJbKoCPrZV4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QID
-AQABo0IwQDAdBgNVHQ4EFgQUVpkHHtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAJ5FdnsX
-SDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPoBP5yCccLqh0l
-VX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq
-URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nf
-peYVhDfwwvJllpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CF
-Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW
-+qtB4Uu2NQvAmxU=
------END CERTIFICATE-----
-
 # Issuer: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903
 # Subject: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903
 # Label: "Certinomis - Root CA"
diff --git a/examples/csharp/helloworld-from-cli/global.json b/examples/csharp/helloworld-from-cli/global.json
deleted file mode 100644
index e4b797e..0000000
--- a/examples/csharp/helloworld-from-cli/global.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "sdk": {
-    "version": "1.0.0"
-  }
-}
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index bd192b4..fc6b31f 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1214,6 +1214,7 @@
                       'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
                       'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
                       'test/core/end2end/tests/retry_non_retriable_status.cc',
+                      'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
                       'test/core/end2end/tests/retry_recv_initial_metadata.cc',
                       'test/core/end2end/tests/retry_recv_message.cc',
                       'test/core/end2end/tests/retry_server_pushback_delay.cc',
diff --git a/grpc.gyp b/grpc.gyp
index a32dec1..b36b166 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -2624,6 +2624,7 @@
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
         'test/core/end2end/tests/retry_non_retriable_status.cc',
+        'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
         'test/core/end2end/tests/retry_recv_initial_metadata.cc',
         'test/core/end2end/tests/retry_recv_message.cc',
         'test/core/end2end/tests/retry_server_pushback_delay.cc',
@@ -2713,6 +2714,7 @@
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc',
         'test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc',
         'test/core/end2end/tests/retry_non_retriable_status.cc',
+        'test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc',
         'test/core/end2end/tests/retry_recv_initial_metadata.cc',
         'test/core/end2end/tests/retry_recv_message.cc',
         'test/core/end2end/tests/retry_server_pushback_delay.cc',
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index a10bfea..33cf565 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -842,10 +842,11 @@
   bool completed_recv_trailing_metadata : 1;
   // State for callback processing.
   bool retry_dispatched : 1;
-  bool recv_initial_metadata_ready_deferred : 1;
-  bool recv_message_ready_deferred : 1;
+  subchannel_batch_data* recv_initial_metadata_ready_deferred_batch;
   grpc_error* recv_initial_metadata_error;
+  subchannel_batch_data* recv_message_ready_deferred_batch;
   grpc_error* recv_message_error;
+  subchannel_batch_data* recv_trailing_metadata_internal_batch;
 } subchannel_call_retry_state;
 
 // Pending batches stored in call data.
@@ -994,6 +995,39 @@
   }
 }
 
+// Frees cached send_initial_metadata.
+static void free_cached_send_initial_metadata(channel_data* chand,
+                                              call_data* calld) {
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: destroying calld->send_initial_metadata", chand,
+            calld);
+  }
+  grpc_metadata_batch_destroy(&calld->send_initial_metadata);
+}
+
+// Frees cached send_message at index idx.
+static void free_cached_send_message(channel_data* chand, call_data* calld,
+                                     size_t idx) {
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR "]",
+            chand, calld, idx);
+  }
+  (*calld->send_messages)[idx]->Destroy();
+}
+
+// Frees cached send_trailing_metadata.
+static void free_cached_send_trailing_metadata(channel_data* chand,
+                                               call_data* calld) {
+  if (grpc_client_channel_trace.enabled()) {
+    gpr_log(GPR_DEBUG,
+            "chand=%p calld=%p: destroying calld->send_trailing_metadata",
+            chand, calld);
+  }
+  grpc_metadata_batch_destroy(&calld->send_trailing_metadata);
+}
+
 // Frees cached send ops that have already been completed after
 // committing the call.
 static void free_cached_send_op_data_after_commit(
@@ -1001,19 +1035,13 @@
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (retry_state->completed_send_initial_metadata) {
-    grpc_metadata_batch_destroy(&calld->send_initial_metadata);
+    free_cached_send_initial_metadata(chand, calld);
   }
   for (size_t i = 0; i < retry_state->completed_send_message_count; ++i) {
-    if (grpc_client_channel_trace.enabled()) {
-      gpr_log(GPR_DEBUG,
-              "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR
-              "]",
-              chand, calld, i);
-    }
-    (*calld->send_messages)[i]->Destroy();
+    free_cached_send_message(chand, calld, i);
   }
   if (retry_state->completed_send_trailing_metadata) {
-    grpc_metadata_batch_destroy(&calld->send_trailing_metadata);
+    free_cached_send_trailing_metadata(chand, calld);
   }
 }
 
@@ -1025,20 +1053,14 @@
   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
   call_data* calld = static_cast<call_data*>(elem->call_data);
   if (batch_data->batch.send_initial_metadata) {
-    grpc_metadata_batch_destroy(&calld->send_initial_metadata);
+    free_cached_send_initial_metadata(chand, calld);
   }
   if (batch_data->batch.send_message) {
-    if (grpc_client_channel_trace.enabled()) {
-      gpr_log(GPR_DEBUG,
-              "chand=%p calld=%p: destroying calld->send_messages[%" PRIuPTR
-              "]",
-              chand, calld, retry_state->completed_send_message_count - 1);
-    }
-    (*calld->send_messages)[retry_state->completed_send_message_count - 1]
-        ->Destroy();
+    free_cached_send_message(chand, calld,
+                             retry_state->completed_send_message_count - 1);
   }
   if (batch_data->batch.send_trailing_metadata) {
-    grpc_metadata_batch_destroy(&calld->send_trailing_metadata);
+    free_cached_send_trailing_metadata(chand, calld);
   }
 }
 
@@ -1642,7 +1664,7 @@
               "(Trailers-Only)",
               chand, calld);
     }
-    retry_state->recv_initial_metadata_ready_deferred = true;
+    retry_state->recv_initial_metadata_ready_deferred_batch = batch_data;
     retry_state->recv_initial_metadata_error = GRPC_ERROR_REF(error);
     if (!retry_state->started_recv_trailing_metadata) {
       // recv_trailing_metadata not yet started by application; start it
@@ -1731,7 +1753,7 @@
               "message and recv_trailing_metadata pending)",
               chand, calld);
     }
-    retry_state->recv_message_ready_deferred = true;
+    retry_state->recv_message_ready_deferred_batch = batch_data;
     retry_state->recv_message_error = GRPC_ERROR_REF(error);
     if (!retry_state->started_recv_trailing_metadata) {
       // recv_trailing_metadata not yet started by application; start it
@@ -1750,6 +1772,59 @@
 }
 
 //
+// list of closures to execute in call combiner
+//
+
+// Represents a closure that needs to run in the call combiner as part of
+// starting or completing a batch.
+typedef struct {
+  grpc_closure* closure;
+  grpc_error* error;
+  const char* reason;
+  bool free_reason = false;
+} closure_to_execute;
+
+static void execute_closures_in_call_combiner(grpc_call_element* elem,
+                                              const char* caller,
+                                              closure_to_execute* closures,
+                                              size_t num_closures) {
+  channel_data* chand = static_cast<channel_data*>(elem->channel_data);
+  call_data* calld = static_cast<call_data*>(elem->call_data);
+  // Note that the call combiner will be yielded for each closure that
+  // we schedule.  We're already running in the call combiner, so one of
+  // the closures can be scheduled directly, but the others will
+  // have to re-enter the call combiner.
+  if (num_closures > 0) {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: %s starting closure: %s", chand,
+              calld, caller, closures[0].reason);
+    }
+    GRPC_CLOSURE_SCHED(closures[0].closure, closures[0].error);
+    if (closures[0].free_reason) {
+      gpr_free(const_cast<char*>(closures[0].reason));
+    }
+    for (size_t i = 1; i < num_closures; ++i) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG,
+                "chand=%p calld=%p: %s starting closure in call combiner: %s",
+                chand, calld, caller, closures[i].reason);
+      }
+      GRPC_CALL_COMBINER_START(calld->call_combiner, closures[i].closure,
+                               closures[i].error, closures[i].reason);
+      if (closures[i].free_reason) {
+        gpr_free(const_cast<char*>(closures[i].reason));
+      }
+    }
+  } else {
+    if (grpc_client_channel_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "chand=%p calld=%p: no closures to run for %s", chand,
+              calld, caller);
+    }
+    GRPC_CALL_COMBINER_STOP(calld->call_combiner, "no closures to run");
+  }
+}
+
+//
 // on_complete callback handling
 //
 
@@ -1777,36 +1852,35 @@
   }
 }
 
-// Represents a closure that needs to run as a result of a completed batch.
-typedef struct {
-  grpc_closure* closure;
-  grpc_error* error;
-  const char* reason;
-} closure_to_execute;
-
 // Adds any necessary closures for deferred recv_initial_metadata and
 // recv_message callbacks to closures, updating *num_closures as needed.
 static void add_closures_for_deferred_recv_callbacks(
     subchannel_batch_data* batch_data, subchannel_call_retry_state* retry_state,
     closure_to_execute* closures, size_t* num_closures) {
-  if (batch_data->batch.recv_trailing_metadata &&
-      retry_state->recv_initial_metadata_ready_deferred) {
-    closure_to_execute* closure = &closures[(*num_closures)++];
-    closure->closure =
-        GRPC_CLOSURE_INIT(&batch_data->recv_initial_metadata_ready,
-                          invoke_recv_initial_metadata_callback, batch_data,
-                          grpc_schedule_on_exec_ctx);
-    closure->error = retry_state->recv_initial_metadata_error;
-    closure->reason = "resuming recv_initial_metadata_ready";
-  }
-  if (batch_data->batch.recv_trailing_metadata &&
-      retry_state->recv_message_ready_deferred) {
-    closure_to_execute* closure = &closures[(*num_closures)++];
-    closure->closure = GRPC_CLOSURE_INIT(&batch_data->recv_message_ready,
-                                         invoke_recv_message_callback,
-                                         batch_data, grpc_schedule_on_exec_ctx);
-    closure->error = retry_state->recv_message_error;
-    closure->reason = "resuming recv_message_ready";
+  if (batch_data->batch.recv_trailing_metadata) {
+    // Add closure for deferred recv_initial_metadata_ready.
+    if (retry_state->recv_initial_metadata_ready_deferred_batch != nullptr) {
+      closure_to_execute* closure = &closures[(*num_closures)++];
+      closure->closure = GRPC_CLOSURE_INIT(
+          &batch_data->recv_initial_metadata_ready,
+          invoke_recv_initial_metadata_callback,
+          retry_state->recv_initial_metadata_ready_deferred_batch,
+          grpc_schedule_on_exec_ctx);
+      closure->error = retry_state->recv_initial_metadata_error;
+      closure->reason = "resuming recv_initial_metadata_ready";
+      retry_state->recv_initial_metadata_ready_deferred_batch = nullptr;
+    }
+    // Add closure for deferred recv_message_ready.
+    if (retry_state->recv_message_ready_deferred_batch != nullptr) {
+      closure_to_execute* closure = &closures[(*num_closures)++];
+      closure->closure = GRPC_CLOSURE_INIT(
+          &batch_data->recv_message_ready, invoke_recv_message_callback,
+          retry_state->recv_message_ready_deferred_batch,
+          grpc_schedule_on_exec_ctx);
+      closure->error = retry_state->recv_message_error;
+      closure->reason = "resuming recv_message_ready";
+      retry_state->recv_message_ready_deferred_batch = nullptr;
+    }
   }
 }
 
@@ -1951,6 +2025,8 @@
   // If we have previously completed recv_trailing_metadata, then the
   // call is finished.
   bool call_finished = retry_state->completed_recv_trailing_metadata;
+  // Record whether we were already committed before receiving this callback.
+  const bool previously_committed = calld->retry_committed;
   // Update bookkeeping in retry_state.
   update_retry_state_for_completed_batch(batch_data, retry_state);
   if (call_finished) {
@@ -1979,35 +2055,39 @@
       if (md_batch->idx.named.grpc_retry_pushback_ms != nullptr) {
         server_pushback_md = &md_batch->idx.named.grpc_retry_pushback_ms->md;
       }
-    } else if (retry_state->completed_recv_trailing_metadata) {
-      call_finished = true;
     }
-    if (call_finished && grpc_client_channel_trace.enabled()) {
-      gpr_log(GPR_DEBUG, "chand=%p calld=%p: call finished, status=%s", chand,
-              calld, grpc_status_code_to_string(status));
-    }
-    // If the call is finished, check if we should retry.
-    if (call_finished &&
-        maybe_retry(elem, batch_data, status, server_pushback_md)) {
-      // Unref batch_data for deferred recv_initial_metadata_ready or
-      // recv_message_ready callbacks, if any.
-      if (batch_data->batch.recv_trailing_metadata &&
-          retry_state->recv_initial_metadata_ready_deferred) {
-        batch_data_unref(batch_data);
-        GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error);
+    // If the call just finished, check if we should retry.
+    if (call_finished) {
+      if (grpc_client_channel_trace.enabled()) {
+        gpr_log(GPR_DEBUG, "chand=%p calld=%p: call finished, status=%s", chand,
+                calld, grpc_status_code_to_string(status));
       }
-      if (batch_data->batch.recv_trailing_metadata &&
-          retry_state->recv_message_ready_deferred) {
+      if (maybe_retry(elem, batch_data, status, server_pushback_md)) {
+        // Unref batch_data for deferred recv_initial_metadata_ready or
+        // recv_message_ready callbacks, if any.
+        if (batch_data->batch.recv_trailing_metadata &&
+            retry_state->recv_initial_metadata_ready_deferred_batch !=
+                nullptr) {
+          batch_data_unref(batch_data);
+          GRPC_ERROR_UNREF(retry_state->recv_initial_metadata_error);
+        }
+        if (batch_data->batch.recv_trailing_metadata &&
+            retry_state->recv_message_ready_deferred_batch != nullptr) {
+          batch_data_unref(batch_data);
+          GRPC_ERROR_UNREF(retry_state->recv_message_error);
+        }
         batch_data_unref(batch_data);
-        GRPC_ERROR_UNREF(retry_state->recv_message_error);
+        return;
       }
-      batch_data_unref(batch_data);
-      return;
+      // Not retrying, so commit the call.
+      retry_commit(elem, retry_state);
     }
   }
-  // If the call is finished or retries are committed, free cached data for
-  // send ops that we've just completed.
-  if (call_finished || calld->retry_committed) {
+  // If we were already committed before receiving this callback, free
+  // cached data for send ops that we've just completed.  (If the call has
+  // just now finished, the call to retry_commit() above will have freed all
+  // cached send ops, so we don't need to do it here.)
+  if (previously_committed) {
     free_cached_send_op_data_for_completed_batch(elem, batch_data, retry_state);
   }
   // Call not being retried.
@@ -2042,20 +2122,8 @@
   // Don't need batch_data anymore.
   batch_data_unref(batch_data);
   // Schedule all of the closures identified above.
-  // Note that the call combiner will be yielded for each closure that
-  // we schedule.  We're already running in the call combiner, so one of
-  // the closures can be scheduled directly, but the others will
-  // have to re-enter the call combiner.
-  if (num_closures > 0) {
-    GRPC_CLOSURE_SCHED(closures[0].closure, closures[0].error);
-    for (size_t i = 1; i < num_closures; ++i) {
-      GRPC_CALL_COMBINER_START(calld->call_combiner, closures[i].closure,
-                               closures[i].error, closures[i].reason);
-    }
-  } else {
-    GRPC_CALL_COMBINER_STOP(calld->call_combiner,
-                            "no closures to run for on_complete");
-  }
+  execute_closures_in_call_combiner(elem, "on_complete", closures,
+                                    num_closures);
 }
 
 //
@@ -2072,6 +2140,31 @@
   grpc_subchannel_call_process_op(subchannel_call, batch);
 }
 
+// Adds a closure to closures that will execute batch in the call combiner.
+static void add_closure_for_subchannel_batch(
+    call_data* calld, grpc_transport_stream_op_batch* batch,
+    closure_to_execute* closures, size_t* num_closures) {
+  batch->handler_private.extra_arg = calld->subchannel_call;
+  GRPC_CLOSURE_INIT(&batch->handler_private.closure,
+                    start_batch_in_call_combiner, batch,
+                    grpc_schedule_on_exec_ctx);
+  closure_to_execute* closure = &closures[(*num_closures)++];
+  closure->closure = &batch->handler_private.closure;
+  closure->error = GRPC_ERROR_NONE;
+  // If the tracer is enabled, we log a more detailed message, which
+  // requires dynamic allocation.  This will be freed in
+  // start_retriable_subchannel_batches().
+  if (grpc_client_channel_trace.enabled()) {
+    char* batch_str = grpc_transport_stream_op_batch_string(batch);
+    gpr_asprintf(const_cast<char**>(&closure->reason),
+                 "starting batch in call combiner: %s", batch_str);
+    gpr_free(batch_str);
+    closure->free_reason = true;
+  } else {
+    closure->reason = "start_subchannel_batch";
+  }
+}
+
 // Adds retriable send_initial_metadata op to batch_data.
 static void add_retriable_send_initial_metadata_op(
     call_data* calld, subchannel_call_retry_state* retry_state,
@@ -2227,8 +2320,12 @@
       static_cast<subchannel_call_retry_state*>(
           grpc_connected_subchannel_call_get_parent_data(
               calld->subchannel_call));
-  subchannel_batch_data* batch_data = batch_data_create(elem, 1);
+  // Create batch_data with 2 refs, since this batch will be unreffed twice:
+  // once when the subchannel batch returns, and again when we actually get
+  // a recv_trailing_metadata op from the surface.
+  subchannel_batch_data* batch_data = batch_data_create(elem, 2);
   add_retriable_recv_trailing_metadata_op(calld, retry_state, batch_data);
+  retry_state->recv_trailing_metadata_internal_batch = batch_data;
   // Note: This will release the call combiner.
   grpc_subchannel_call_process_op(calld->subchannel_call, &batch_data->batch);
 }
@@ -2299,7 +2396,7 @@
 // *num_batches as needed.
 static void add_subchannel_batches_for_pending_batches(
     grpc_call_element* elem, subchannel_call_retry_state* retry_state,
-    grpc_transport_stream_op_batch** batches, size_t* num_batches) {
+    closure_to_execute* closures, size_t* num_closures) {
   call_data* calld = static_cast<call_data*>(elem->call_data);
   for (size_t i = 0; i < GPR_ARRAY_SIZE(calld->pending_batches); ++i) {
     pending_batch* pending = &calld->pending_batches[i];
@@ -2342,13 +2439,37 @@
     }
     if (batch->recv_trailing_metadata &&
         retry_state->started_recv_trailing_metadata) {
+      // If we previously completed a recv_trailing_metadata op
+      // initiated by start_internal_recv_trailing_metadata(), use the
+      // result of that instead of trying to re-start this op.
+      if (retry_state->recv_trailing_metadata_internal_batch != nullptr) {
+        // If the batch completed, then trigger the completion callback
+        // directly, so that we return the previously returned results to
+        // the application.  Otherwise, just unref the internally
+        // started subchannel batch, since we'll propagate the
+        // completion when it completes.
+        if (retry_state->completed_recv_trailing_metadata) {
+          subchannel_batch_data* batch_data =
+              retry_state->recv_trailing_metadata_internal_batch;
+          closure_to_execute* closure = &closures[(*num_closures)++];
+          closure->closure = &batch_data->on_complete;
+          // Batches containing recv_trailing_metadata always succeed.
+          closure->error = GRPC_ERROR_NONE;
+          closure->reason =
+              "re-executing on_complete for recv_trailing_metadata "
+              "to propagate internally triggered result";
+        } else {
+          batch_data_unref(retry_state->recv_trailing_metadata_internal_batch);
+        }
+        retry_state->recv_trailing_metadata_internal_batch = nullptr;
+      }
       continue;
     }
     // If we're not retrying, just send the batch as-is.
     if (calld->method_params == nullptr ||
         calld->method_params->retry_policy() == nullptr ||
         calld->retry_committed) {
-      batches[(*num_batches)++] = batch;
+      add_closure_for_subchannel_batch(calld, batch, closures, num_closures);
       pending_batch_clear(calld, pending);
       continue;
     }
@@ -2385,7 +2506,8 @@
       GPR_ASSERT(batch->collect_stats);
       add_retriable_recv_trailing_metadata_op(calld, retry_state, batch_data);
     }
-    batches[(*num_batches)++] = &batch_data->batch;
+    add_closure_for_subchannel_batch(calld, &batch_data->batch, closures,
+                                     num_closures);
   }
 }
 
@@ -2403,62 +2525,29 @@
       static_cast<subchannel_call_retry_state*>(
           grpc_connected_subchannel_call_get_parent_data(
               calld->subchannel_call));
+  // Construct list of closures to execute, one for each pending batch.
   // We can start up to 6 batches.
-  grpc_transport_stream_op_batch*
-      batches[GPR_ARRAY_SIZE(calld->pending_batches)];
-  size_t num_batches = 0;
+  closure_to_execute closures[GPR_ARRAY_SIZE(calld->pending_batches)];
+  size_t num_closures = 0;
   // Replay previously-returned send_* ops if needed.
   subchannel_batch_data* replay_batch_data =
       maybe_create_subchannel_batch_for_replay(elem, retry_state);
   if (replay_batch_data != nullptr) {
-    batches[num_batches++] = &replay_batch_data->batch;
+    add_closure_for_subchannel_batch(calld, &replay_batch_data->batch, closures,
+                                     &num_closures);
   }
   // Now add pending batches.
-  add_subchannel_batches_for_pending_batches(elem, retry_state, batches,
-                                             &num_batches);
+  add_subchannel_batches_for_pending_batches(elem, retry_state, closures,
+                                             &num_closures);
   // Start batches on subchannel call.
-  // Note that the call combiner will be yielded for each batch that we
-  // send down.  We're already running in the call combiner, so one of
-  // the batches can be started directly, but the others will have to
-  // re-enter the call combiner.
   if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: starting %" PRIuPTR
             " retriable batches on subchannel_call=%p",
-            chand, calld, num_batches, calld->subchannel_call);
+            chand, calld, num_closures, calld->subchannel_call);
   }
-  if (num_batches == 0) {
-    // This should be fairly rare, but it can happen when (e.g.) an
-    // attempt completes before it has finished replaying all
-    // previously sent messages.
-    GRPC_CALL_COMBINER_STOP(calld->call_combiner,
-                            "no retriable subchannel batches to start");
-  } else {
-    for (size_t i = 1; i < num_batches; ++i) {
-      if (grpc_client_channel_trace.enabled()) {
-        char* batch_str = grpc_transport_stream_op_batch_string(batches[i]);
-        gpr_log(GPR_DEBUG,
-                "chand=%p calld=%p: starting batch in call combiner: %s", chand,
-                calld, batch_str);
-        gpr_free(batch_str);
-      }
-      batches[i]->handler_private.extra_arg = calld->subchannel_call;
-      GRPC_CLOSURE_INIT(&batches[i]->handler_private.closure,
-                        start_batch_in_call_combiner, batches[i],
-                        grpc_schedule_on_exec_ctx);
-      GRPC_CALL_COMBINER_START(calld->call_combiner,
-                               &batches[i]->handler_private.closure,
-                               GRPC_ERROR_NONE, "start_subchannel_batch");
-    }
-    if (grpc_client_channel_trace.enabled()) {
-      char* batch_str = grpc_transport_stream_op_batch_string(batches[0]);
-      gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting batch: %s", chand, calld,
-              batch_str);
-      gpr_free(batch_str);
-    }
-    // Note: This will release the call combiner.
-    grpc_subchannel_call_process_op(calld->subchannel_call, batches[0]);
-  }
+  execute_closures_in_call_combiner(elem, "start_retriable_subchannel_batches",
+                                    closures, num_closures);
 }
 
 //
diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc
index fb29fa7..4e8b8b7 100644
--- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc
+++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc
@@ -326,7 +326,7 @@
 
 static const grpc_handshaker_vtable http_connect_handshaker_vtable = {
     http_connect_handshaker_destroy, http_connect_handshaker_shutdown,
-    http_connect_handshaker_do_handshake};
+    http_connect_handshaker_do_handshake, "http_connect"};
 
 static grpc_handshaker* grpc_http_connect_handshaker_create() {
   http_connect_handshaker* handshaker =
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
index fb24357..e86ab5a 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc
@@ -153,7 +153,10 @@
   /* If there are no pending queries, invoke on_done callback and destroy the
      request */
   if (gpr_unref(&r->pending_queries)) {
-    grpc_cares_wrapper_address_sorting_sort(*(r->lb_addrs_out));
+    grpc_lb_addresses* lb_addrs = *(r->lb_addrs_out);
+    if (lb_addrs != nullptr) {
+      grpc_cares_wrapper_address_sorting_sort(lb_addrs);
+    }
     GRPC_CLOSURE_SCHED(r->on_done, r->error);
     gpr_mu_destroy(&r->mu);
     grpc_ares_ev_driver_destroy(r->ev_driver);
diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc
index 66a86c2..e49d532 100644
--- a/src/core/lib/channel/channel_args.cc
+++ b/src/core/lib/channel/channel_args.cc
@@ -411,3 +411,31 @@
   arg.value.pointer.vtable = vtable;
   return arg;
 }
+
+char* grpc_channel_args_string(const grpc_channel_args* args) {
+  if (args == nullptr) return nullptr;
+  gpr_strvec v;
+  gpr_strvec_init(&v);
+  for (size_t i = 0; i < args->num_args; ++i) {
+    const grpc_arg& arg = args->args[i];
+    char* s;
+    switch (arg.type) {
+      case GRPC_ARG_INTEGER:
+        gpr_asprintf(&s, "%s=%d", arg.key, arg.value.integer);
+        break;
+      case GRPC_ARG_STRING:
+        gpr_asprintf(&s, "%s=%s", arg.key, arg.value.string);
+        break;
+      case GRPC_ARG_POINTER:
+        gpr_asprintf(&s, "%s=%p", arg.key, arg.value.pointer.p);
+        break;
+      default:
+        gpr_asprintf(&s, "arg with unknown type");
+    }
+    gpr_strvec_add(&v, s);
+  }
+  char* result =
+      gpr_strjoin_sep(const_cast<const char**>(v.strs), v.count, ", ", nullptr);
+  gpr_strvec_destroy(&v);
+  return result;
+}
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index c0d6a17..5ff303a 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -124,4 +124,8 @@
 grpc_arg grpc_channel_arg_pointer_create(char* name, void* value,
                                          const grpc_arg_pointer_vtable* vtable);
 
+// Returns a string representing channel args in human-readable form.
+// Callers takes ownership of result.
+char* grpc_channel_args_string(const grpc_channel_args* args);
+
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/lib/channel/handshaker.cc b/src/core/lib/channel/handshaker.cc
index 9b1af8d..9cd9782 100644
--- a/src/core/lib/channel/handshaker.cc
+++ b/src/core/lib/channel/handshaker.cc
@@ -22,11 +22,15 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/handshaker.h"
+#include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/timer.h"
 
+grpc_core::TraceFlag grpc_handshaker_trace(false, "handshaker");
+
 //
 // grpc_handshaker
 //
@@ -52,6 +56,10 @@
                                    args);
 }
 
+const char* grpc_handshaker_name(grpc_handshaker* handshaker) {
+  return handshaker->vtable->name;
+}
+
 //
 // grpc_handshake_manager
 //
@@ -127,6 +135,12 @@
 
 void grpc_handshake_manager_add(grpc_handshake_manager* mgr,
                                 grpc_handshaker* handshaker) {
+  if (grpc_handshaker_trace.enabled()) {
+    gpr_log(
+        GPR_DEBUG,
+        "handshake_manager %p: adding handshaker %s [%p] at index %" PRIuPTR,
+        mgr, grpc_handshaker_name(handshaker), handshaker, mgr->count);
+  }
   gpr_mu_lock(&mgr->mu);
   // To avoid allocating memory for each handshaker we add, we double
   // the number of elements every time we need more.
@@ -172,23 +186,56 @@
   GRPC_ERROR_UNREF(why);
 }
 
+static char* handshaker_args_string(grpc_handshaker_args* args) {
+  char* args_str = grpc_channel_args_string(args->args);
+  size_t num_args = args->args != nullptr ? args->args->num_args : 0;
+  size_t read_buffer_length =
+      args->read_buffer != nullptr ? args->read_buffer->length : 0;
+  char* str;
+  gpr_asprintf(&str,
+               "{endpoint=%p, args=%p {size=%" PRIuPTR
+               ": %s}, read_buffer=%p (length=%" PRIuPTR "), exit_early=%d}",
+               args->endpoint, args->args, num_args, args_str,
+               args->read_buffer, read_buffer_length, args->exit_early);
+  gpr_free(args_str);
+  return str;
+}
+
 // Helper function to call either the next handshaker or the
 // on_handshake_done callback.
 // Returns true if we've scheduled the on_handshake_done callback.
 static bool call_next_handshaker_locked(grpc_handshake_manager* mgr,
                                         grpc_error* error) {
+  if (grpc_handshaker_trace.enabled()) {
+    char* args_str = handshaker_args_string(&mgr->args);
+    gpr_log(GPR_DEBUG,
+            "handshake_manager %p: error=%s shutdown=%d index=%" PRIuPTR
+            ", args=%s",
+            mgr, grpc_error_string(error), mgr->shutdown, mgr->index, args_str);
+    gpr_free(args_str);
+  }
   GPR_ASSERT(mgr->index <= mgr->count);
   // If we got an error or we've been shut down or we're exiting early or
   // we've finished the last handshaker, invoke the on_handshake_done
   // callback.  Otherwise, call the next handshaker.
   if (error != GRPC_ERROR_NONE || mgr->shutdown || mgr->args.exit_early ||
       mgr->index == mgr->count) {
+    if (grpc_handshaker_trace.enabled()) {
+      gpr_log(GPR_DEBUG, "handshake_manager %p: handshaking complete", mgr);
+    }
     // Cancel deadline timer, since we're invoking the on_handshake_done
     // callback now.
     grpc_timer_cancel(&mgr->deadline_timer);
     GRPC_CLOSURE_SCHED(&mgr->on_handshake_done, error);
     mgr->shutdown = true;
   } else {
+    if (grpc_handshaker_trace.enabled()) {
+      gpr_log(
+          GPR_DEBUG,
+          "handshake_manager %p: calling handshaker %s [%p] at index %" PRIuPTR,
+          mgr, grpc_handshaker_name(mgr->handshakers[mgr->index]),
+          mgr->handshakers[mgr->index], mgr->index);
+    }
     grpc_handshaker_do_handshake(mgr->handshakers[mgr->index], mgr->acceptor,
                                  &mgr->call_next_handshaker, &mgr->args);
   }
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index dfecd81..be7fd12 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -84,6 +84,9 @@
                        grpc_tcp_server_acceptor* acceptor,
                        grpc_closure* on_handshake_done,
                        grpc_handshaker_args* args);
+
+  /// The name of the handshaker, for debugging purposes.
+  const char* name;
 } grpc_handshaker_vtable;
 
 /// Base struct.  To subclass, make this the first member of the
@@ -102,6 +105,7 @@
                                   grpc_tcp_server_acceptor* acceptor,
                                   grpc_closure* on_handshake_done,
                                   grpc_handshaker_args* args);
+const char* grpc_handshaker_name(grpc_handshaker* handshaker);
 
 ///
 /// grpc_handshake_manager
diff --git a/src/core/lib/security/transport/security_handshaker.cc b/src/core/lib/security/transport/security_handshaker.cc
index 0c97dfa..57dd340 100644
--- a/src/core/lib/security/transport/security_handshaker.cc
+++ b/src/core/lib/security/transport/security_handshaker.cc
@@ -406,7 +406,7 @@
 
 static const grpc_handshaker_vtable security_handshaker_vtable = {
     security_handshaker_destroy, security_handshaker_shutdown,
-    security_handshaker_do_handshake};
+    security_handshaker_do_handshake, "security"};
 
 static grpc_handshaker* security_handshaker_create(
     tsi_handshaker* handshaker, grpc_security_connector* connector) {
@@ -456,7 +456,7 @@
 
 static const grpc_handshaker_vtable fail_handshaker_vtable = {
     fail_handshaker_destroy, fail_handshaker_shutdown,
-    fail_handshaker_do_handshake};
+    fail_handshaker_do_handshake, "security_fail"};
 
 static grpc_handshaker* fail_handshaker_create() {
   grpc_handshaker* h = static_cast<grpc_handshaker*>(gpr_malloc(sizeof(*h)));
diff --git a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
index f1b85c3..309e33d 100644
--- a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
+++ b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
@@ -1,13 +1,5 @@
 <Project>
   <ItemGroup>
-    <!-- We are relying on run_tests.py to build grpc_csharp_ext with the right bitness
-    and we copy it as both x86 (needed by net45) and x64 (needed by netcoreapp1.0) as we don't
-    know which one will be needed to run the tests. -->
-    <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib">
-      <Link>libgrpc_csharp_ext.x86.dylib</Link>
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-      <Pack>false</Pack>
-    </Content>
     <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib">
       <Link>libgrpc_csharp_ext.x64.dylib</Link>
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index f7a7a5c..6e28c11 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -2,6 +2,6 @@
 <Project>
   <PropertyGroup>
     <GrpcCsharpVersion>1.12.0-dev</GrpcCsharpVersion>
-    <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
+    <GoogleProtobufVersion>3.5.1</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/global.json b/src/csharp/global.json
deleted file mode 100644
index 815be4b..0000000
--- a/src/csharp/global.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "sdk": {
-    "version": "2.1.4"
-  }
-}
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 2833062..bfb1fd3 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -108,7 +108,10 @@
                                    serverName:(NSString *)serverName
                                       timeout:(NSTimeInterval)timeout
                               completionQueue:(GRPCCompletionQueue *)queue {
-  GRPCChannel *channel;
+  // The __block attribute is to allow channel take refcount inside @synchronized block. Without
+  // this attribute, retain of channel object happens after objc_sync_exit in release builds, which
+  // may result in channel released before used. See grpc/#15033.
+  __block GRPCChannel *channel;
   // This is racing -[GRPCHost disconnect].
   @synchronized(self) {
     if (!_channel) {
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index 60d309e..35c0982 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -57,7 +57,7 @@
 }
 
 INSTALL_REQUIRES = (
-    'protobuf>=3.5.0.post1',
+    'protobuf>=3.5.2.post1',
     'grpcio>={version}'.format(version=grpc_version.VERSION),
 )
 
diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py
index 10c4c38..589d0ff 100644
--- a/src/python/grpcio_reflection/setup.py
+++ b/src/python/grpcio_reflection/setup.py
@@ -58,7 +58,7 @@
 }
 
 INSTALL_REQUIRES = (
-    'protobuf>=3.5.0.post1',
+    'protobuf>=3.5.2.post1',
     'grpcio>={version}'.format(version=grpc_version.VERSION),
 )
 
diff --git a/src/python/grpcio_testing/setup.py b/src/python/grpcio_testing/setup.py
index 5a9d593..eb480a5 100644
--- a/src/python/grpcio_testing/setup.py
+++ b/src/python/grpcio_testing/setup.py
@@ -29,7 +29,7 @@
 }
 
 INSTALL_REQUIRES = (
-    'protobuf>=3.5.0.post1',
+    'protobuf>=3.5.2.post1',
     'grpcio>={version}'.format(version=grpc_version.VERSION),
 )
 
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index 4e0f672..98ac19d 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -41,7 +41,7 @@
     'grpcio>={version}'.format(version=grpc_version.VERSION),
     'grpcio-tools>={version}'.format(version=grpc_version.VERSION),
     'grpcio-health-checking>={version}'.format(version=grpc_version.VERSION),
-    'oauth2client>=1.4.7', 'protobuf>=3.5.0.post1', 'six>=1.10',
+    'oauth2client>=1.4.7', 'protobuf>=3.5.2.post1', 'six>=1.10',
     'google-auth>=1.0.0', 'requests>=2.14.2')
 
 COMMAND_CLASS = {
diff --git a/src/python/grpcio_tests/tests/_loader.py b/src/python/grpcio_tests/tests/_loader.py
index 3168091..be0af646 100644
--- a/src/python/grpcio_tests/tests/_loader.py
+++ b/src/python/grpcio_tests/tests/_loader.py
@@ -54,7 +54,7 @@
         for module in modules:
             try:
                 package_paths = module.__path__
-            except:
+            except AttributeError:
                 continue
             self.walk_packages(package_paths)
         coverage_context.stop()
diff --git a/src/python/grpcio_tests/tests/_result.py b/src/python/grpcio_tests/tests/_result.py
index 9907c4e..b105f18 100644
--- a/src/python/grpcio_tests/tests/_result.py
+++ b/src/python/grpcio_tests/tests/_result.py
@@ -46,7 +46,7 @@
       None.
   """
 
-    class Kind:
+    class Kind(object):
         UNTESTED = 'untested'
         RUNNING = 'running'
         ERROR = 'error'
@@ -257,7 +257,7 @@
         #coverage.Coverage().combine()
 
 
-class _Colors:
+class _Colors(object):
     """Namespaced constants for terminal color magic numbers."""
     HEADER = '\033[95m'
     INFO = '\033[94m'
diff --git a/src/python/grpcio_tests/tests/interop/client.py b/src/python/grpcio_tests/tests/interop/client.py
index 3780ed9..698c370 100644
--- a/src/python/grpcio_tests/tests/interop/client.py
+++ b/src/python/grpcio_tests/tests/interop/client.py
@@ -66,10 +66,6 @@
     return parser.parse_args()
 
 
-def _application_default_credentials():
-    return oauth2client_client.GoogleCredentials.get_application_default()
-
-
 def _stub(args):
     target = '{}:{}'.format(args.server_host, args.server_port)
     if args.test_case == 'oauth2_auth_token':
diff --git a/src/python/grpcio_tests/tests/protoc_plugin/beta_python_plugin_test.py b/src/python/grpcio_tests/tests/protoc_plugin/beta_python_plugin_test.py
index ad0ecf0..b46e533 100644
--- a/src/python/grpcio_tests/tests/protoc_plugin/beta_python_plugin_test.py
+++ b/src/python/grpcio_tests/tests/protoc_plugin/beta_python_plugin_test.py
@@ -329,9 +329,7 @@
 
         _packagify(self._python_out)
 
-        with _system_path([
-                self._python_out,
-        ]):
+        with _system_path([self._python_out]):
             self._payload_pb2 = importlib.import_module(_PAYLOAD_PB2)
             self._requests_pb2 = importlib.import_module(_REQUESTS_PB2)
             self._responses_pb2 = importlib.import_module(_RESPONSES_PB2)
diff --git a/src/python/grpcio_tests/tests/stress/test_runner.py b/src/python/grpcio_tests/tests/stress/test_runner.py
index d5038e3..764cda1 100644
--- a/src/python/grpcio_tests/tests/stress/test_runner.py
+++ b/src/python/grpcio_tests/tests/stress/test_runner.py
@@ -50,7 +50,7 @@
                 test_case.test_interoperability(self._stub, None)
                 end_time = time.time()
                 self._histogram.add((end_time - start_time) * 1e9)
-            except Exception as e:
+            except Exception as e:  # pylint: disable=broad-except
                 traceback.print_exc()
                 self._exception_queue.put(
                     Exception("An exception occured during test {}"
diff --git a/src/python/grpcio_tests/tests/testing/_client_application.py b/src/python/grpcio_tests/tests/testing/_client_application.py
index 7d0d74c..3ddeba2 100644
--- a/src/python/grpcio_tests/tests/testing/_client_application.py
+++ b/src/python/grpcio_tests/tests/testing/_client_application.py
@@ -215,30 +215,6 @@
         return _UNSATISFACTORY_OUTCOME
 
 
-def run(scenario, channel):
-    stub = services_pb2_grpc.FirstServiceStub(channel)
-    try:
-        if scenario is Scenario.UNARY_UNARY:
-            return _run_unary_unary(stub)
-        elif scenario is Scenario.UNARY_STREAM:
-            return _run_unary_stream(stub)
-        elif scenario is Scenario.STREAM_UNARY:
-            return _run_stream_unary(stub)
-        elif scenario is Scenario.STREAM_STREAM:
-            return _run_stream_stream(stub)
-        elif scenario is Scenario.CONCURRENT_STREAM_UNARY:
-            return _run_concurrent_stream_unary(stub)
-        elif scenario is Scenario.CONCURRENT_STREAM_STREAM:
-            return _run_concurrent_stream_stream(stub)
-        elif scenario is Scenario.CANCEL_UNARY_UNARY:
-            return _run_cancel_unary_unary(stub)
-        elif scenario is Scenario.INFINITE_REQUEST_STREAM:
-            return _run_infinite_request_stream(stub)
-    except grpc.RpcError as rpc_error:
-        return Outcome(Outcome.Kind.RPC_ERROR, rpc_error.code(),
-                       rpc_error.details())
-
-
 _IMPLEMENTATIONS = {
     Scenario.UNARY_UNARY: _run_unary_unary,
     Scenario.UNARY_STREAM: _run_unary_stream,
diff --git a/src/python/grpcio_tests/tests/testing/_server_application.py b/src/python/grpcio_tests/tests/testing/_server_application.py
index 02769ca..243c385 100644
--- a/src/python/grpcio_tests/tests/testing/_server_application.py
+++ b/src/python/grpcio_tests/tests/testing/_server_application.py
@@ -38,7 +38,7 @@
             context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
             context.set_details('Something is wrong with your request!')
         return
-        yield services_pb2.Strange()
+        yield services_pb2.Strange()  # pylint: disable=unreachable
 
     def StreUn(self, request_iterator, context):
         context.send_initial_metadata(((
diff --git a/src/python/grpcio_tests/tests/unit/_compression_test.py b/src/python/grpcio_tests/tests/unit/_compression_test.py
index 7550cd3..0b11f03 100644
--- a/src/python/grpcio_tests/tests/unit/_compression_test.py
+++ b/src/python/grpcio_tests/tests/unit/_compression_test.py
@@ -52,9 +52,9 @@
         self.stream_unary = None
         self.stream_stream = None
         if self.request_streaming and self.response_streaming:
-            self.stream_stream = lambda x, y: handle_stream(x, y)
+            self.stream_stream = handle_stream
         elif not self.request_streaming and not self.response_streaming:
-            self.unary_unary = lambda x, y: handle_unary(x, y)
+            self.unary_unary = handle_unary
 
 
 class _GenericHandler(grpc.GenericRpcHandler):
diff --git a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
index 9045ff5..23f5ef6 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
@@ -285,7 +285,7 @@
         self.assertEqual(5, len(server_event.batch_operations))
         found_server_op_types = set()
         for server_result in server_event.batch_operations:
-            self.assertNotIn(client_result.type(), found_server_op_types)
+            self.assertNotIn(server_result.type(), found_server_op_types)
             found_server_op_types.add(server_result.type())
             if server_result.type() == cygrpc.OperationType.receive_message:
                 self.assertEqual(REQUEST, server_result.message())
diff --git a/src/python/grpcio_tests/tests/unit/_cython/test_utilities.py b/src/python/grpcio_tests/tests/unit/_cython/test_utilities.py
index 4a00b9e..7d5eaaa 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/test_utilities.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/test_utilities.py
@@ -25,7 +25,7 @@
         def wrapped_function():
             try:
                 self._result = function(*args, **kwargs)
-            except Exception as error:
+            except Exception as error:  # pylint: disable=broad-except
                 self._error = error
 
         self._result = None
@@ -41,7 +41,7 @@
         self._thread.join()
         if self._error:
             # TODO(atash): re-raise exceptions in a way that preserves tracebacks
-            raise self._error
+            raise self._error  # pylint: disable=raising-bad-type
         return self._result
 
 
diff --git a/src/python/grpcio_tests/tests/unit/_exit_test.py b/src/python/grpcio_tests/tests/unit/_exit_test.py
index 6e6d9de..f40f3ae 100644
--- a/src/python/grpcio_tests/tests/unit/_exit_test.py
+++ b/src/python/grpcio_tests/tests/unit/_exit_test.py
@@ -49,7 +49,7 @@
         for process in processes:
             try:
                 process.kill()
-            except Exception:
+            except Exception:  # pylint: disable=broad-except
                 pass
 
 
diff --git a/src/python/grpcio_tests/tests/unit/_from_grpc_import_star.py b/src/python/grpcio_tests/tests/unit/_from_grpc_import_star.py
index e683131..ad847ae 100644
--- a/src/python/grpcio_tests/tests/unit/_from_grpc_import_star.py
+++ b/src/python/grpcio_tests/tests/unit/_from_grpc_import_star.py
@@ -14,7 +14,7 @@
 
 _BEFORE_IMPORT = tuple(globals())
 
-from grpc import *
+from grpc import *  # pylint: disable=wildcard-import
 
 _AFTER_IMPORT = tuple(globals())
 
diff --git a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
index e40cca8..93a5fdf 100644
--- a/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
+++ b/src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
@@ -165,11 +165,13 @@
 
     def __next__(self):
         if self._current >= self._high:
-            raise Exception("This is a deliberate failure in a unit test.")
+            raise test_control.Defect()
         else:
             self._current += 1
             return self._bytestring
 
+    next = __next__
+
 
 def _unary_unary_multi_callable(channel):
     return channel.unary_unary(_UNARY_UNARY)
diff --git a/src/python/grpcio_tests/tests/unit/beta/_beta_features_test.py b/src/python/grpcio_tests/tests/unit/beta/_beta_features_test.py
index 61c03f6..b43c647 100644
--- a/src/python/grpcio_tests/tests/unit/beta/_beta_features_test.py
+++ b/src/python/grpcio_tests/tests/unit/beta/_beta_features_test.py
@@ -65,7 +65,7 @@
             self._serviced = True
             self._condition.notify_all()
             return
-            yield
+            yield  # pylint: disable=unreachable
 
     def stream_unary(self, request_iterator, context):
         for request in request_iterator:
diff --git a/templates/src/csharp/Grpc.Core/Version.csproj.include.template b/templates/src/csharp/Grpc.Core/Version.csproj.include.template
index 5bc66e9..398b198 100755
--- a/templates/src/csharp/Grpc.Core/Version.csproj.include.template
+++ b/templates/src/csharp/Grpc.Core/Version.csproj.include.template
@@ -4,6 +4,6 @@
   <Project>
     <PropertyGroup>
       <GrpcCsharpVersion>${settings.csharp_version}</GrpcCsharpVersion>
-      <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
+      <GoogleProtobufVersion>3.5.1</GoogleProtobufVersion>
     </PropertyGroup>
   </Project>
diff --git a/templates/tools/dockerfile/python_deps.include b/templates/tools/dockerfile/python_deps.include
index ce36de8..c7bf238 100644
--- a/templates/tools/dockerfile/python_deps.include
+++ b/templates/tools/dockerfile/python_deps.include
@@ -9,6 +9,6 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
diff --git a/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
index b250566..d70ad94 100644
--- a/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/cxx_alpine_x64/Dockerfile.template
@@ -40,7 +40,7 @@
     zip
   
   # Install Python packages from PyPI
-  RUN pip install --upgrade pip==9.0.2
+  RUN pip install --upgrade pip==10.0.1
   RUN pip install virtualenv
   RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
   
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.cc b/test/core/client_channel/resolvers/dns_resolver_test.cc
index e3fba28..103b291 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_test.cc
@@ -70,11 +70,12 @@
 
   test_succeeds(dns, "dns:10.2.1.1");
   test_succeeds(dns, "dns:10.2.1.1:1234");
-  test_succeeds(dns, "ipv4:www.google.com");
+  test_succeeds(dns, "dns:www.google.com");
+  test_succeeds(dns, "dns:///www.google.com");
   if (grpc_resolve_address == grpc_resolve_address_ares) {
-    test_succeeds(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
+    test_succeeds(dns, "dns://8.8.8.8/8.8.8.8:8888");
   } else {
-    test_fails(dns, "ipv4://8.8.8.8/8.8.8.8:8888");
+    test_fails(dns, "dns://8.8.8.8/8.8.8.8:8888");
   }
 
   {
diff --git a/test/core/end2end/end2end_nosec_tests.cc b/test/core/end2end/end2end_nosec_tests.cc
index 297408c..59eb643 100644
--- a/test/core/end2end/end2end_nosec_tests.cc
+++ b/test/core/end2end/end2end_nosec_tests.cc
@@ -132,6 +132,8 @@
 extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
 extern void retry_non_retriable_status(grpc_end2end_test_config config);
 extern void retry_non_retriable_status_pre_init(void);
+extern void retry_non_retriable_status_before_recv_trailing_metadata_started(grpc_end2end_test_config config);
+extern void retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init(void);
 extern void retry_recv_initial_metadata(grpc_end2end_test_config config);
 extern void retry_recv_initial_metadata_pre_init(void);
 extern void retry_recv_message(grpc_end2end_test_config config);
@@ -236,6 +238,7 @@
   retry_exceeds_buffer_size_in_initial_batch_pre_init();
   retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
   retry_non_retriable_status_pre_init();
+  retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init();
   retry_recv_initial_metadata_pre_init();
   retry_recv_message_pre_init();
   retry_server_pushback_delay_pre_init();
@@ -320,6 +323,7 @@
     retry_exceeds_buffer_size_in_initial_batch(config);
     retry_exceeds_buffer_size_in_subsequent_batch(config);
     retry_non_retriable_status(config);
+    retry_non_retriable_status_before_recv_trailing_metadata_started(config);
     retry_recv_initial_metadata(config);
     retry_recv_message(config);
     retry_server_pushback_delay(config);
@@ -552,6 +556,10 @@
       retry_non_retriable_status(config);
       continue;
     }
+    if (0 == strcmp("retry_non_retriable_status_before_recv_trailing_metadata_started", argv[i])) {
+      retry_non_retriable_status_before_recv_trailing_metadata_started(config);
+      continue;
+    }
     if (0 == strcmp("retry_recv_initial_metadata", argv[i])) {
       retry_recv_initial_metadata(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.cc b/test/core/end2end/end2end_tests.cc
index 9b3f655..9f164b4 100644
--- a/test/core/end2end/end2end_tests.cc
+++ b/test/core/end2end/end2end_tests.cc
@@ -134,6 +134,8 @@
 extern void retry_exceeds_buffer_size_in_subsequent_batch_pre_init(void);
 extern void retry_non_retriable_status(grpc_end2end_test_config config);
 extern void retry_non_retriable_status_pre_init(void);
+extern void retry_non_retriable_status_before_recv_trailing_metadata_started(grpc_end2end_test_config config);
+extern void retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init(void);
 extern void retry_recv_initial_metadata(grpc_end2end_test_config config);
 extern void retry_recv_initial_metadata_pre_init(void);
 extern void retry_recv_message(grpc_end2end_test_config config);
@@ -239,6 +241,7 @@
   retry_exceeds_buffer_size_in_initial_batch_pre_init();
   retry_exceeds_buffer_size_in_subsequent_batch_pre_init();
   retry_non_retriable_status_pre_init();
+  retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init();
   retry_recv_initial_metadata_pre_init();
   retry_recv_message_pre_init();
   retry_server_pushback_delay_pre_init();
@@ -324,6 +327,7 @@
     retry_exceeds_buffer_size_in_initial_batch(config);
     retry_exceeds_buffer_size_in_subsequent_batch(config);
     retry_non_retriable_status(config);
+    retry_non_retriable_status_before_recv_trailing_metadata_started(config);
     retry_recv_initial_metadata(config);
     retry_recv_message(config);
     retry_server_pushback_delay(config);
@@ -560,6 +564,10 @@
       retry_non_retriable_status(config);
       continue;
     }
+    if (0 == strcmp("retry_non_retriable_status_before_recv_trailing_metadata_started", argv[i])) {
+      retry_non_retriable_status_before_recv_trailing_metadata_started(config);
+      continue;
+    }
     if (0 == strcmp("retry_recv_initial_metadata", argv[i])) {
       retry_recv_initial_metadata(config);
       continue;
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index c7b03625..c355fc2 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -170,6 +170,9 @@
                                       proxyable=False),
     'retry_non_retriable_status': default_test_options._replace(
         cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
+    'retry_non_retriable_status_before_recv_trailing_metadata_started':
+        default_test_options._replace(
+            cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
     'retry_recv_initial_metadata': default_test_options._replace(
         cpu_cost=LOWCPU, needs_client_channel=True, proxyable=False),
     'retry_recv_message': default_test_options._replace(
diff --git a/test/core/end2end/generate_tests.bzl b/test/core/end2end/generate_tests.bzl
index 37fd183..11fc576 100755
--- a/test/core/end2end/generate_tests.bzl
+++ b/test/core/end2end/generate_tests.bzl
@@ -158,6 +158,8 @@
         needs_client_channel=True, proxyable=False),
     'retry_non_retriable_status': test_options(needs_client_channel=True,
                                                proxyable=False),
+    'retry_non_retriable_status_before_recv_trailing_metadata_started':
+        test_options(needs_client_channel=True, proxyable=False),
     'retry_recv_initial_metadata': test_options(needs_client_channel=True,
                                                 proxyable=False),
     'retry_recv_message': test_options(needs_client_channel=True,
diff --git a/test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc b/test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
new file mode 100644
index 0000000..eb016a3
--- /dev/null
+++ b/test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc
@@ -0,0 +1,266 @@
+/*
+ *
+ * Copyright 2018 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/transport/static_metadata.h"
+
+#include "test/core/end2end/cq_verifier.h"
+#include "test/core/end2end/tests/cancel_test_helpers.h"
+
+static void* tag(intptr_t t) { return (void*)t; }
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char* test_name,
+                                            grpc_channel_args* client_args,
+                                            grpc_channel_args* server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "Running test: %s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_from_now(int n) {
+  return grpc_timeout_seconds_to_deadline(n);
+}
+
+static gpr_timespec five_seconds_from_now(void) {
+  return n_seconds_from_now(5);
+}
+
+static void drain_cq(grpc_completion_queue* cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_from_now(), nullptr);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture* f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->shutdown_cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(f->shutdown_cq, tag(1000),
+                                         grpc_timeout_seconds_to_deadline(5),
+                                         nullptr)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = nullptr;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture* f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = nullptr;
+}
+
+static void end_test(grpc_end2end_test_fixture* f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+  grpc_completion_queue_destroy(f->shutdown_cq);
+}
+
+// Tests that we don't retry for non-retryable status codes, even if
+// status is received before the recv_trailing_metadata op is started.
+// - 1 retry allowed for ABORTED status
+// - first attempt gets INVALID_ARGUMENT, so no retry is done
+static void
+test_retry_non_retriable_status_before_recv_trailing_metadata_started(
+    grpc_end2end_test_config config) {
+  grpc_call* c;
+  grpc_call* s;
+  grpc_op ops[6];
+  grpc_op* op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_slice request_payload_slice = grpc_slice_from_static_string("foo");
+  grpc_slice response_payload_slice = grpc_slice_from_static_string("bar");
+  grpc_byte_buffer* request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  grpc_byte_buffer* response_payload =
+      grpc_raw_byte_buffer_create(&response_payload_slice, 1);
+  grpc_byte_buffer* request_payload_recv = nullptr;
+  grpc_byte_buffer* response_payload_recv = nullptr;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char* peer;
+
+  grpc_arg arg;
+  arg.type = GRPC_ARG_STRING;
+  arg.key = const_cast<char*>(GRPC_ARG_SERVICE_CONFIG);
+  arg.value.string = const_cast<char*>(
+      "{\n"
+      "  \"methodConfig\": [ {\n"
+      "    \"name\": [\n"
+      "      { \"service\": \"service\", \"method\": \"method\" }\n"
+      "    ],\n"
+      "    \"retryPolicy\": {\n"
+      "      \"maxAttempts\": 2,\n"
+      "      \"initialBackoff\": \"1s\",\n"
+      "      \"maxBackoff\": \"120s\",\n"
+      "      \"backoffMultiplier\": 1.6,\n"
+      "      \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
+      "    }\n"
+      "  } ]\n"
+      "}");
+  grpc_channel_args client_args = {1, &arg};
+  grpc_end2end_test_fixture f =
+      begin_test(config, "retry_non_retriable_status", &client_args, nullptr);
+
+  cq_verifier* cqv = cq_verifier_create(f.cq);
+
+  gpr_timespec deadline = five_seconds_from_now();
+  c = grpc_channel_create_call(f.client, nullptr, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               grpc_slice_from_static_string("/service/method"),
+                               nullptr, deadline, nullptr);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op++;
+  op->op = GRPC_OP_RECV_MESSAGE;
+  op->data.recv_message.recv_message = &response_payload_recv;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != nullptr);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_INVALID_ARGUMENT;
+  op->data.send_status_from_server.status_details = &status_details;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
+  cq_verify(cqv);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), nullptr);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(2), true);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_INVALID_ARGUMENT);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/service/method"));
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(response_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+  grpc_byte_buffer_destroy(response_payload_recv);
+
+  grpc_call_unref(c);
+  grpc_call_unref(s);
+
+  cq_verifier_destroy(cqv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void retry_non_retriable_status_before_recv_trailing_metadata_started(
+    grpc_end2end_test_config config) {
+  GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL);
+  test_retry_non_retriable_status_before_recv_trailing_metadata_started(config);
+}
+
+void retry_non_retriable_status_before_recv_trailing_metadata_started_pre_init() {
+}
diff --git a/test/core/gprpp/ref_counted_ptr_test.cc b/test/core/gprpp/ref_counted_ptr_test.cc
index 2e398a7..c810345 100644
--- a/test/core/gprpp/ref_counted_ptr_test.cc
+++ b/test/core/gprpp/ref_counted_ptr_test.cc
@@ -88,7 +88,7 @@
 
 TEST(RefCountedPtr, CopyAssignmentToSelf) {
   RefCountedPtr<Foo> foo(New<Foo>());
-  foo = foo;
+  foo = *&foo;  // The "*&" avoids warnings from LLVM -Wself-assign.
 }
 
 TEST(RefCountedPtr, EnclosedScope) {
diff --git a/test/core/handshake/readahead_handshaker_server_ssl.cc b/test/core/handshake/readahead_handshaker_server_ssl.cc
index 9788320..97e9c20 100644
--- a/test/core/handshake/readahead_handshaker_server_ssl.cc
+++ b/test/core/handshake/readahead_handshaker_server_ssl.cc
@@ -64,7 +64,7 @@
 
 const grpc_handshaker_vtable readahead_handshaker_vtable = {
     readahead_handshaker_destroy, readahead_handshaker_shutdown,
-    readahead_handshaker_do_handshake};
+    readahead_handshaker_do_handshake, "read_ahead"};
 
 static grpc_handshaker* readahead_handshaker_create() {
   grpc_handshaker* h =
diff --git a/test/cpp/naming/address_sorting_test.cc b/test/cpp/naming/address_sorting_test.cc
index df93ff6..a423733 100644
--- a/test/cpp/naming/address_sorting_test.cc
+++ b/test/cpp/naming/address_sorting_test.cc
@@ -722,16 +722,24 @@
 }
 
 int main(int argc, char** argv) {
-  const char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
+  char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
   if (resolver == nullptr || strlen(resolver) == 0) {
     gpr_setenv("GRPC_DNS_RESOLVER", "ares");
   } else if (strcmp("ares", resolver)) {
     gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver);
   }
+  gpr_free(resolver);
   grpc_test_init(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
   grpc_init();
   auto result = RUN_ALL_TESTS();
   grpc_shutdown();
+  // Test sequential and nested inits and shutdowns.
+  grpc_init();
+  grpc_init();
+  grpc_shutdown();
+  grpc_shutdown();
+  grpc_init();
+  grpc_shutdown();
   return result;
 }
diff --git a/third_party/address_sorting/address_sorting.c b/third_party/address_sorting/address_sorting.c
index ec46099..d62aca3 100644
--- a/third_party/address_sorting/address_sorting.c
+++ b/third_party/address_sorting/address_sorting.c
@@ -366,4 +366,5 @@
     abort();
   }
   g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory);
+  g_current_source_addr_factory = NULL;
 }
diff --git a/third_party/protobuf b/third_party/protobuf
index 2761122..b5fbb74 160000
--- a/third_party/protobuf
+++ b/third_party/protobuf
@@ -1 +1 @@
-Subproject commit 2761122b810fe8861004ae785cc3ab39f384d342
+Subproject commit b5fbb742af122b565925987e65c08957739976a7
diff --git a/tools/distrib/pylint_code.sh b/tools/distrib/pylint_code.sh
index 307fe6c..013b666 100755
--- a/tools/distrib/pylint_code.sh
+++ b/tools/distrib/pylint_code.sh
@@ -30,10 +30,11 @@
 )
 
 VIRTUALENV=python_pylint_venv
+python -m virtualenv $VIRTUALENV
 
-virtualenv $VIRTUALENV
-PYTHON=$(realpath $VIRTUALENV/bin/python)
-$PYTHON -m pip install --upgrade pip==9.0.2
+PYTHON=$VIRTUALENV/bin/python
+
+$PYTHON -m pip install --upgrade pip==10.0.1
 $PYTHON -m pip install pylint==1.6.5
 
 for dir in "${DIRS[@]}"; do
diff --git a/tools/distrib/python/docgen.py b/tools/distrib/python/docgen.py
index 4d6fcb5..732d948 100755
--- a/tools/distrib/python/docgen.py
+++ b/tools/distrib/python/docgen.py
@@ -70,7 +70,7 @@
         'env': environment
     },
     {
-        'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip==9.0.1'],
+        'args': [VIRTUALENV_PIP_PATH, 'install', '--upgrade', 'pip==10.0.1'],
         'env': environment
     },
     {
diff --git a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
index 2c65fca..a0e1419 100644
--- a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
+++ b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
@@ -20,4 +20,4 @@
 CC_INCLUDE='third_party/protobuf/src'
 PROTO_INCLUDE='third_party/protobuf/src'
 
-PROTOBUF_SUBMODULE_VERSION="2761122b810fe8861004ae785cc3ab39f384d342"
+PROTOBUF_SUBMODULE_VERSION="b5fbb742af122b565925987e65c08957739976a7"
diff --git a/tools/distrib/yapf_code.sh b/tools/distrib/yapf_code.sh
index 919e9c1..dbc842f 100755
--- a/tools/distrib/yapf_code.sh
+++ b/tools/distrib/yapf_code.sh
@@ -32,7 +32,7 @@
 
 virtualenv $VIRTUALENV
 PYTHON=$(realpath "${VIRTUALENV}/bin/python")
-$PYTHON -m pip install --upgrade pip==9.0.2
+$PYTHON -m pip install --upgrade pip==10.0.1
 $PYTHON -m pip install --upgrade futures
 $PYTHON -m pip install yapf==0.20.0
 
diff --git a/tools/dockerfile/grpc_clang_tidy/Dockerfile b/tools/dockerfile/grpc_clang_tidy/Dockerfile
index d9599af..dec7680 100644
--- a/tools/dockerfile/grpc_clang_tidy/Dockerfile
+++ b/tools/dockerfile/grpc_clang_tidy/Dockerfile
@@ -33,9 +33,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 ADD clang_tidy_all_the_things.sh /
 
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index 96154c8..e806ba5 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -60,9 +60,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #================
 # C# dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index 96154c8..e806ba5 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -60,9 +60,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #================
 # C# dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
index 3e0f477..d3eb456 100644
--- a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
@@ -60,9 +60,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index 83f05d8..b136259 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
@@ -28,9 +28,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
index 79907f3..d43d0e4 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
@@ -28,9 +28,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
index 4206941..17ca678 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
@@ -28,9 +28,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
index c14bcda..e7555c9 100644
--- a/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
@@ -28,9 +28,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 RUN pip install twisted h2==2.6.1 hyper
 
diff --git a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
index 510e157..fc29ada 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
@@ -43,9 +43,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 
 # Trigger download of as many Gradle artifacts as possible.
diff --git a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
index 510e157..fc29ada 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
@@ -43,9 +43,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 
 # Trigger download of as many Gradle artifacts as possible.
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index 7464e31..539a869 100644
--- a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -60,9 +60,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Node dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index 49c1191..97cdf48 100644
--- a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -60,9 +60,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
index f3667b5..75e3314 100644
--- a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
@@ -60,9 +60,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Ruby dependencies
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
index c9335f0..7a8e26d 100644
--- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #================
 # C# dependencies
diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
index 5b2b527..3449af1 100644
--- a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -38,7 +38,7 @@
   zip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index 825896b..f251753 100644
--- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
index 692960d..bb9c751 100644
--- a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
index 38b040b..b0d9261 100644
--- a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
index 5487b6d..65ff58e 100644
--- a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile
index ffb0858..e926443 100644
--- a/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1710_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/fuzzer/Dockerfile b/tools/dockerfile/test/fuzzer/Dockerfile
index 3671219..a242492 100644
--- a/tools/dockerfile/test/fuzzer/Dockerfile
+++ b/tools/dockerfile/test/fuzzer/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index 8202a4a..962fe97 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -140,9 +140,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Install coverage for Python test coverage reporting
 RUN pip install coverage
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index e87eb6f..f32b437 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -75,9 +75,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Node dependencies
diff --git a/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
index 3a63867..e96be27 100644
--- a/tools/dockerfile/test/php7_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
@@ -75,9 +75,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
index 32a4b61..88ee267 100644
--- a/tools/dockerfile/test/php_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # PHP dependencies
diff --git a/tools/dockerfile/test/python_alpine_x64/Dockerfile b/tools/dockerfile/test/python_alpine_x64/Dockerfile
index 66ec34a..6e06e2d 100644
--- a/tools/dockerfile/test/python_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/python_alpine_x64/Dockerfile
@@ -37,7 +37,7 @@
   zip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
 RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0
 
diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile
index 4e6916d..41b670c 100644
--- a/tools/dockerfile/test/python_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/python_pyenv_x64/Dockerfile b/tools/dockerfile/test/python_pyenv_x64/Dockerfile
index bd1432e..24fe7b2 100644
--- a/tools/dockerfile/test/python_pyenv_x64/Dockerfile
+++ b/tools/dockerfile/test/python_pyenv_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 # Install dependencies for pyenv
 RUN apt-get update && apt-get install -y \
diff --git a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
index 45923ca..37d909a 100644
--- a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Ruby dependencies
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index c93693c..4885843 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -64,9 +64,9 @@
     python-pip
 
 # Install Python packages from PyPI
-RUN pip install --upgrade pip==9.0.2
+RUN pip install --upgrade pip==10.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.2.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/gce/linux_kokoro_performance_worker_init.sh b/tools/gce/linux_kokoro_performance_worker_init.sh
index 084e9fb..4a1e3e6 100755
--- a/tools/gce/linux_kokoro_performance_worker_init.sh
+++ b/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -72,7 +72,7 @@
 sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
 
 # Python dependencies
-sudo pip install --upgrade pip==9.0.2
+sudo pip install --upgrade pip==10.0.1
 sudo pip install tabulate
 sudo pip install google-api-python-client
 sudo pip install virtualenv
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 09d8fd0..7222cef 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -72,7 +72,7 @@
 sudo apt-get install -y libgflags-dev libgtest-dev libc++-dev clang
 
 # Python dependencies
-sudo pip install --upgrade pip==9.0.2
+sudo pip install --upgrade pip==10.0.1
 sudo pip install tabulate
 sudo pip install google-api-python-client
 sudo pip install virtualenv
diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
index 47c1d4b..d84bebd 100644
--- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc
+++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc
@@ -67,7 +67,7 @@
 export PYTHONPATH=/Library/Python/3.4/site-packages
 
 # set xcode version for Obj-C tests
-sudo xcode-select -switch /Applications/Xcode_8.2.1.app/Contents/Developer
+sudo xcode-select -switch /Applications/Xcode_9.2.app/Contents/Developer/
 
 # TODO(jtattermusch): better debugging of clock skew, remove once not needed
 date
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
index 93d2858..3102992 100755
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh
@@ -37,7 +37,7 @@
 # TODO(adelez): implement size for test targets and change test_timeout back
 "${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
   --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
-  test --jobs="100" \
+  test --jobs="200" \
   --test_output=errors  \
   --verbose_failures=true  \
   --keep_going  \
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
index ed5caa4..882e4df 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_dbg.sh
@@ -13,6 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,3600 --runs_per_test_detects_flakes --runs_per_test=2"
+EXTRA_FLAGS="-c dbg --test_timeout=300,450,1200,3600 --runs_per_test_detects_flakes --runs_per_test=1"
 github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
 
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
index 66f02a8..85f6953 100644
--- a/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry_opt.sh
@@ -13,5 +13,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,3600 --runs_per_test_detects_flakes --runs_per_test=2"
+EXTRA_FLAGS="-c opt --test_timeout=300,450,1200,3600 --runs_per_test_detects_flakes --runs_per_test=1"
 github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}"
diff --git a/tools/internal_ci/linux/grpc_msan_on_foundry.sh b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
index 60b30ff..6858d97 100644
--- a/tools/internal_ci/linux/grpc_msan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_msan_on_foundry.sh
@@ -37,7 +37,7 @@
 
 "${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
   --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
-  test --jobs="100" \
+  test --jobs="200" \
   --test_timeout="3600,3600,3600,3600" \
   --test_output=errors  \
   --verbose_failures=true  \
diff --git a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
index a87547d..0f0c12d 100644
--- a/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
+++ b/tools/internal_ci/linux/grpc_ubsan_on_foundry.sh
@@ -37,7 +37,7 @@
 
 "${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
   --host_jvm_args=-Dbazel.DigestFunction=SHA256 \
-  test --jobs="100" \
+  test --jobs="200" \
   --test_timeout="3600,3600,3600,3600" \
   --test_output=errors  \
   --verbose_failures=true  \
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 1e4d401..74b3707 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -8584,6 +8584,7 @@
       "test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc", 
       "test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc", 
       "test/core/end2end/tests/retry_non_retriable_status.cc", 
+      "test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc", 
       "test/core/end2end/tests/retry_recv_initial_metadata.cc", 
       "test/core/end2end/tests/retry_recv_message.cc", 
       "test/core/end2end/tests/retry_server_pushback_delay.cc", 
@@ -8682,6 +8683,7 @@
       "test/core/end2end/tests/retry_exceeds_buffer_size_in_initial_batch.cc", 
       "test/core/end2end/tests/retry_exceeds_buffer_size_in_subsequent_batch.cc", 
       "test/core/end2end/tests/retry_non_retriable_status.cc", 
+      "test/core/end2end/tests/retry_non_retriable_status_before_recv_trailing_metadata_started.cc", 
       "test/core/end2end/tests/retry_recv_initial_metadata.cc", 
       "test/core/end2end/tests/retry_recv_message.cc", 
       "test/core/end2end/tests/retry_server_pushback_delay.cc", 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index d8c1a12..067d9b3 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -8031,6 +8031,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -9737,6 +9760,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -11415,6 +11461,28 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -14316,6 +14384,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -15837,6 +15928,25 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -17424,6 +17534,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -19153,6 +19286,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -20953,6 +21109,30 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -22706,6 +22886,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -24482,6 +24685,30 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -31161,6 +31388,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -34016,6 +34266,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -36665,6 +36938,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -38348,6 +38644,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -41227,6 +41546,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -42729,6 +43071,25 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -44293,6 +44654,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+trace_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -45999,6 +46383,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+workarounds_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -47775,6 +48182,30 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_http_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -49505,6 +49936,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
@@ -55989,6 +56443,29 @@
   }, 
   {
     "args": [
+      "retry_non_retriable_status_before_recv_trailing_metadata_started"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "retry_recv_initial_metadata"
     ], 
     "ci_platforms": [
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
index bd95272..b0a6f0f 100755
--- a/tools/run_tests/helper_scripts/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -163,7 +163,7 @@
   ;;
 esac
 
-$VENV_PYTHON -m pip install --upgrade pip==9.0.2
+$VENV_PYTHON -m pip install --upgrade pip==10.0.1
 $VENV_PYTHON -m pip install setuptools
 $VENV_PYTHON -m pip install cython
 $VENV_PYTHON -m pip install six enum34 protobuf futures
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 4146eec..6fb0f89 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -921,9 +921,6 @@
             if self.platform == 'mac':
                 # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
                 self._make_options = ['EMBED_OPENSSL=true']
-                if self.args.compiler != 'coreclr':
-                    # On Mac, official distribution of mono is 32bit.
-                    self._make_options += ['ARCH_FLAGS=-m32', 'LDFLAGS=-m32']
             else:
                 self._make_options = ['EMBED_OPENSSL=true', 'EMBED_ZLIB=true']
 
@@ -944,6 +941,9 @@
             assembly_subdir += '/net45'
             if self.platform == 'windows':
                 runtime_cmd = []
+            elif self.platform == 'mac':
+                # mono before version 5.2 on MacOS defaults to 32bit runtime
+                runtime_cmd = ['mono', '--arch=64']
             else:
                 runtime_cmd = ['mono']
 
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index b22bbd6..723d185 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -31,7 +31,7 @@
  886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
  30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0)
  ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
- 2761122b810fe8861004ae785cc3ab39f384d342 third_party/protobuf (v3.5.0)
+ b5fbb742af122b565925987e65c08957739976a7 third_party/protobuf (v3.5.2)
  cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
  3be1924221e1326df520f8498d704a5c4c8d0cce third_party/cares/cares (cares-1_13_0)
  73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty