Add grpc_channel_get_info() to C-core API.
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 587d86c..dbd125e 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -237,6 +237,10 @@
     created for. */
 GRPCAPI char *grpc_channel_get_target(grpc_channel *channel);
 
+/** Request info about the channel. */
+GRPCAPI void grpc_channel_get_info(grpc_channel *channel,
+                                   grpc_channel_info *channel_info);
+
 /** Create a client channel to 'target'. Additional channel level configuration
     MAY be provided by grpc_channel_args, though the expectation is that most
     clients will want to simply pass NULL. See grpc_channel_args definition for
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 0be7ab2..0fc86b5 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -467,6 +467,13 @@
   } data;
 } grpc_op;
 
+/** Information requested from the channel. */
+typedef struct {
+  /* If non-NULL, will be set to point to a string indicating the LB
+   * policy name.  Caller takes ownership. */
+  char **lb_policy_name;
+} grpc_channel_info;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/ext/census/grpc_filter.c b/src/core/ext/census/grpc_filter.c
index a4cf6f3..7ace2f6 100644
--- a/src/core/ext/census/grpc_filter.c
+++ b/src/core/ext/census/grpc_filter.c
@@ -191,6 +191,7 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "census-client"};
 
 const grpc_channel_filter grpc_server_census_filter = {
@@ -204,4 +205,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "census-server"};
diff --git a/src/core/ext/client_channel/client_channel.c b/src/core/ext/client_channel/client_channel.c
index 80b4f04..d15af0b 100644
--- a/src/core/ext/client_channel/client_channel.c
+++ b/src/core/ext/client_channel/client_channel.c
@@ -39,6 +39,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
@@ -123,6 +124,7 @@
   /** mutex protecting all variables below in this data structure */
   gpr_mu mu;
   /** currently active load balancer */
+  char* lb_policy_name;
   grpc_lb_policy *lb_policy;
   /** maps method names to method_parameters structs */
   grpc_mdstr_hash_table *method_params_table;
@@ -223,6 +225,7 @@
 static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
                                        grpc_error *error) {
   channel_data *chand = arg;
+  char *lb_policy_name = NULL;
   grpc_lb_policy *lb_policy = NULL;
   grpc_lb_policy *old_lb_policy;
   grpc_mdstr_hash_table *method_params_table = NULL;
@@ -236,12 +239,11 @@
     lb_policy_args.client_channel_factory = chand->client_channel_factory;
 
     // Find LB policy name.
-    const char *lb_policy_name = NULL;
     const grpc_arg *channel_arg =
         grpc_channel_args_find(lb_policy_args.args, GRPC_ARG_LB_POLICY_NAME);
     if (channel_arg != NULL) {
       GPR_ASSERT(channel_arg->type == GRPC_ARG_STRING);
-      lb_policy_name = channel_arg->value.string;
+      lb_policy_name = gpr_strdup(channel_arg->value.string);
     }
     // Special case: If all of the addresses are balancer addresses,
     // assume that we should use the grpclb policy, regardless of what the
@@ -265,13 +267,14 @@
                   "addresses, no backend addresses -- forcing use of grpclb LB "
                   "policy",
                   lb_policy_name);
+          gpr_free(lb_policy_name);
         }
-        lb_policy_name = "grpclb";
+        lb_policy_name = gpr_strdup("grpclb");
       }
     }
     // Use pick_first if nothing was specified and we didn't select grpclb
     // above.
-    if (lb_policy_name == NULL) lb_policy_name = "pick_first";
+    if (lb_policy_name == NULL) lb_policy_name = gpr_strdup("pick_first");
 
     lb_policy =
         grpc_lb_policy_create(exec_ctx, lb_policy_name, &lb_policy_args);
@@ -299,6 +302,10 @@
   }
 
   gpr_mu_lock(&chand->mu);
+  if (lb_policy_name != NULL) {
+    gpr_free(chand->lb_policy_name);
+    chand->lb_policy_name = lb_policy_name;
+  }
   old_lb_policy = chand->lb_policy;
   chand->lb_policy = lb_policy;
   if (chand->method_params_table != NULL) {
@@ -426,6 +433,18 @@
   gpr_mu_unlock(&chand->mu);
 }
 
+static void cc_get_channel_info(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem,
+                                grpc_channel_info *info) {
+  channel_data *chand = elem->channel_data;
+  gpr_mu_lock(&chand->mu);
+  if (info->lb_policy_name != NULL) {
+    *info->lb_policy_name = chand->lb_policy_name == NULL
+                                ? NULL : gpr_strdup(chand->lb_policy_name);
+  }
+  gpr_mu_unlock(&chand->mu);
+}
+
 /* Constructor for channel_data */
 static void cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem,
@@ -465,6 +484,7 @@
                                      chand->interested_parties);
     GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
   }
+  gpr_free(chand->lb_policy_name);
   if (chand->method_params_table != NULL) {
     grpc_mdstr_hash_table_unref(chand->method_params_table);
   }
@@ -1048,6 +1068,7 @@
     cc_init_channel_elem,
     cc_destroy_channel_elem,
     cc_get_peer,
+    cc_get_channel_info,
     "client-channel",
 };
 
diff --git a/src/core/ext/load_reporting/load_reporting_filter.c b/src/core/ext/load_reporting/load_reporting_filter.c
index eeae240..b810e20 100644
--- a/src/core/ext/load_reporting/load_reporting_filter.c
+++ b/src/core/ext/load_reporting/load_reporting_filter.c
@@ -232,4 +232,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "load_reporting"};
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 2c53679..3370f0e 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -255,6 +255,13 @@
   return next_elem->filter->get_peer(exec_ctx, next_elem);
 }
 
+void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem,
+                                grpc_channel_info *channel_info) {
+  grpc_channel_element *next_elem = elem + 1;
+  return next_elem->filter->get_channel_info(exec_ctx, next_elem, channel_info);
+}
+
 void grpc_channel_next_op(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
                           grpc_transport_op *op) {
   grpc_channel_element *next_elem = elem + 1;
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index 27f3be7..6fbcd87 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -156,6 +156,10 @@
   /* Implement grpc_call_get_peer() */
   char *(*get_peer)(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
 
+  /* Implement grpc_channel_get_info() */
+  void (*get_channel_info)(grpc_exec_ctx *exec_ctx, grpc_channel_element *elem,
+                           grpc_channel_info *channel_info);
+
   /* The name of this filter */
   const char *name;
 } grpc_channel_filter;
@@ -273,6 +277,10 @@
                           grpc_transport_op *op);
 /* Pass through a request to get_peer to the next child element */
 char *grpc_call_next_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem);
+/* Pass through a request to get_channel_info() to the next child element */
+void grpc_channel_next_get_info(grpc_exec_ctx *exec_ctx,
+                                grpc_channel_element *elem,
+                                grpc_channel_info *channel_info);
 
 /* Given the top element of a channel stack, get the channel stack itself */
 grpc_channel_stack *grpc_channel_stack_from_top_element(
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 0981d59..7968cf7 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -328,4 +328,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "compress"};
diff --git a/src/core/lib/channel/connected_channel.c b/src/core/lib/channel/connected_channel.c
index 918379c..6ae2b3b 100644
--- a/src/core/lib/channel/connected_channel.c
+++ b/src/core/lib/channel/connected_channel.c
@@ -134,6 +134,11 @@
   return grpc_transport_get_peer(exec_ctx, chand->transport);
 }
 
+/* No-op. */
+static void con_get_channel_info(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem,
+                                 grpc_channel_info *channel_info) {}
+
 static const grpc_channel_filter connected_channel_filter = {
     con_start_transport_stream_op,
     con_start_transport_op,
@@ -145,6 +150,7 @@
     init_channel_elem,
     destroy_channel_elem,
     con_get_peer,
+    con_get_channel_info,
     "connected",
 };
 
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index d2ea525..224c823 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -316,6 +316,7 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "deadline",
 };
 
@@ -330,5 +331,6 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "deadline",
 };
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index 1dc05fb..b5ab4dd 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -448,4 +448,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "http-client"};
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index f2221fb..d02a765 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -344,4 +344,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "http-server"};
diff --git a/src/core/lib/channel/message_size_filter.c b/src/core/lib/channel/message_size_filter.c
index 7dc5ae0..bbcd2a2 100644
--- a/src/core/lib/channel/message_size_filter.c
+++ b/src/core/lib/channel/message_size_filter.c
@@ -248,4 +248,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "message_size"};
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index b366d14..3a96af2 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -351,4 +351,5 @@
                                                      init_channel_elem,
                                                      destroy_channel_elem,
                                                      grpc_call_next_get_peer,
+                                                     grpc_channel_next_get_info,
                                                      "client-auth"};
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index b2c6815..8ecc5fd 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -278,4 +278,5 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "server-auth"};
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index 92d783b..22bf85b 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -175,6 +175,15 @@
   return gpr_strdup(channel->target);
 }
 
+void grpc_channel_get_info(grpc_channel *channel,
+                           grpc_channel_info *channel_info) {
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_channel_element *elem =
+      grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
+  elem->filter->get_channel_info(&exec_ctx, elem, channel_info);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
 static grpc_call *grpc_channel_create_call_internal(
     grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
     grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index d32c884..6fd1dd9 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -88,6 +88,10 @@
   return NULL;
 }
 
+static void lame_get_channel_info(grpc_exec_ctx *exec_ctx,
+                                  grpc_channel_element *elem,
+                                  grpc_channel_info *channel_info) {}
+
 static void lame_start_transport_op(grpc_exec_ctx *exec_ctx,
                                     grpc_channel_element *elem,
                                     grpc_transport_op *op) {
@@ -140,6 +144,7 @@
     init_channel_elem,
     destroy_channel_elem,
     lame_get_peer,
+    lame_get_channel_info,
     "lame-client",
 };
 
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 3a90308..914b62e 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -965,6 +965,7 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "server",
 };
 
diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c
index 844db5e..857ba6b 100644
--- a/test/core/client_channel/lb_policies_test.c
+++ b/test/core/client_channel/lb_policies_test.c
@@ -638,6 +638,21 @@
   test_spec_destroy(spec);
 }
 
+static void test_get_channel_info() {
+  grpc_channel *channel = grpc_insecure_channel_create(
+      "test:127.0.0.1:1234?lb_policy=round_robin", NULL, NULL);
+  // Ensures that resolver returns.
+  grpc_channel_check_connectivity_state(channel, true /* try_to_connect */);
+  char *lb_policy_name = NULL;
+  grpc_channel_info channel_info;
+  channel_info.lb_policy_name = &lb_policy_name;
+  grpc_channel_get_info(channel, &channel_info);
+  GPR_ASSERT(lb_policy_name != NULL);
+  GPR_ASSERT(strcmp(lb_policy_name, "round_robin") == 0);
+  gpr_free(lb_policy_name);
+  grpc_channel_destroy(channel);
+}
+
 static void print_failed_expectations(const int *expected_connection_sequence,
                                       const int *actual_connection_sequence,
                                       const size_t expected_seq_length,
@@ -933,6 +948,7 @@
 
   test_pending_calls(4);
   test_ping();
+  test_get_channel_info();
 
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_shutdown();
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index 0e5692f..2f8a2a4 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -231,6 +231,7 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "filter_call_init_fails"};
 
 /*******************************************************************************
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index d5eddc7..da55414 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -258,6 +258,7 @@
     init_channel_elem,
     destroy_channel_elem,
     grpc_call_next_get_peer,
+    grpc_channel_next_get_info,
     "filter_causes_close"};
 
 /*******************************************************************************