|  | @@ -239,9 +239,9 @@ class ChannelData {
 | 
	
		
			
				|  |  |    void DestroyResolvingLoadBalancingPolicyLocked();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    static bool ProcessResolverResultLocked(
 | 
	
		
			
				|  |  | -      void* arg, const Resolver::Result& result, const char** lb_policy_name,
 | 
	
		
			
				|  |  | +      void* arg, const Resolver::Result& result,
 | 
	
		
			
				|  |  |        RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
 | 
	
		
			
				|  |  | -      grpc_error** service_config_error);
 | 
	
		
			
				|  |  | +      grpc_error** service_config_error, bool* no_valid_service_config);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_error* DoPingLocked(grpc_transport_op* op);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -252,7 +252,6 @@ class ChannelData {
 | 
	
		
			
				|  |  |    void ProcessLbPolicy(
 | 
	
		
			
				|  |  |        const Resolver::Result& resolver_result,
 | 
	
		
			
				|  |  |        const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
 | 
	
		
			
				|  |  | -      grpc_core::UniquePtr<char>* lb_policy_name,
 | 
	
		
			
				|  |  |        RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    //
 | 
	
	
		
			
				|  | @@ -1620,24 +1619,23 @@ void ChannelData::DestroyResolvingLoadBalancingPolicyLocked() {
 | 
	
		
			
				|  |  |  void ChannelData::ProcessLbPolicy(
 | 
	
		
			
				|  |  |      const Resolver::Result& resolver_result,
 | 
	
		
			
				|  |  |      const internal::ClientChannelGlobalParsedConfig* parsed_service_config,
 | 
	
		
			
				|  |  | -    grpc_core::UniquePtr<char>* lb_policy_name,
 | 
	
		
			
				|  |  |      RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config) {
 | 
	
		
			
				|  |  | -  // Prefer the LB policy name found in the service config.
 | 
	
		
			
				|  |  | +  // Prefer the LB policy config found in the service config.
 | 
	
		
			
				|  |  |    if (parsed_service_config != nullptr &&
 | 
	
		
			
				|  |  |        parsed_service_config->parsed_lb_config() != nullptr) {
 | 
	
		
			
				|  |  | -    lb_policy_name->reset(
 | 
	
		
			
				|  |  | -        gpr_strdup(parsed_service_config->parsed_lb_config()->name()));
 | 
	
		
			
				|  |  |      *lb_policy_config = parsed_service_config->parsed_lb_config();
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  const char* local_policy_name = nullptr;
 | 
	
		
			
				|  |  | +  // Try the deprecated LB policy name from the service config.
 | 
	
		
			
				|  |  | +  // If not, try the setting from channel args.
 | 
	
		
			
				|  |  | +  const char* policy_name = nullptr;
 | 
	
		
			
				|  |  |    if (parsed_service_config != nullptr &&
 | 
	
		
			
				|  |  |        parsed_service_config->parsed_deprecated_lb_policy() != nullptr) {
 | 
	
		
			
				|  |  | -    local_policy_name = parsed_service_config->parsed_deprecated_lb_policy();
 | 
	
		
			
				|  |  | +    policy_name = parsed_service_config->parsed_deprecated_lb_policy();
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      const grpc_arg* channel_arg =
 | 
	
		
			
				|  |  |          grpc_channel_args_find(resolver_result.args, GRPC_ARG_LB_POLICY_NAME);
 | 
	
		
			
				|  |  | -    local_policy_name = grpc_channel_arg_get_string(channel_arg);
 | 
	
		
			
				|  |  | +    policy_name = grpc_channel_arg_get_string(channel_arg);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Special case: If at least one balancer address is present, we use
 | 
	
		
			
				|  |  |    // the grpclb policy, regardless of what the resolver has returned.
 | 
	
	
		
			
				|  | @@ -1650,27 +1648,46 @@ void ChannelData::ProcessLbPolicy(
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (found_balancer_address) {
 | 
	
		
			
				|  |  | -    if (local_policy_name != nullptr &&
 | 
	
		
			
				|  |  | -        strcmp(local_policy_name, "grpclb") != 0) {
 | 
	
		
			
				|  |  | +    if (policy_name != nullptr && strcmp(policy_name, "grpclb") != 0) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  |                "resolver requested LB policy %s but provided at least one "
 | 
	
		
			
				|  |  |                "balancer address -- forcing use of grpclb LB policy",
 | 
	
		
			
				|  |  | -              local_policy_name);
 | 
	
		
			
				|  |  | +              policy_name);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    local_policy_name = "grpclb";
 | 
	
		
			
				|  |  | +    policy_name = "grpclb";
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Use pick_first if nothing was specified and we didn't select grpclb
 | 
	
		
			
				|  |  |    // above.
 | 
	
		
			
				|  |  | -  lb_policy_name->reset(gpr_strdup(
 | 
	
		
			
				|  |  | -      local_policy_name == nullptr ? "pick_first" : local_policy_name));
 | 
	
		
			
				|  |  | +  if (policy_name == nullptr) policy_name = "pick_first";
 | 
	
		
			
				|  |  | +  // Now that we have the policy name, construct an empty config for it.
 | 
	
		
			
				|  |  | +  Json config_json = Json::Array{Json::Object{
 | 
	
		
			
				|  |  | +      {policy_name, Json::Object{}},
 | 
	
		
			
				|  |  | +  }};
 | 
	
		
			
				|  |  | +  grpc_error* parse_error = GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  | +  *lb_policy_config = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
 | 
	
		
			
				|  |  | +      config_json, &parse_error);
 | 
	
		
			
				|  |  | +  // The policy name came from one of three places:
 | 
	
		
			
				|  |  | +  // - The deprecated loadBalancingPolicy field in the service config,
 | 
	
		
			
				|  |  | +  //   in which case the code in ClientChannelServiceConfigParser
 | 
	
		
			
				|  |  | +  //   already verified that the policy does not require a config.
 | 
	
		
			
				|  |  | +  // - One of the hard-coded values here, all of which are known to not
 | 
	
		
			
				|  |  | +  //   require a config.
 | 
	
		
			
				|  |  | +  // - A channel arg, in which case the application did something that
 | 
	
		
			
				|  |  | +  //   is a misuse of our API.
 | 
	
		
			
				|  |  | +  // In the first two cases, these assertions will always be true.  In
 | 
	
		
			
				|  |  | +  // the last case, this is probably fine for now.
 | 
	
		
			
				|  |  | +  // TODO(roth): If the last case becomes a problem, add better error
 | 
	
		
			
				|  |  | +  // handling here.
 | 
	
		
			
				|  |  | +  GPR_ASSERT(*lb_policy_config != nullptr);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(parse_error == GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Synchronous callback from ResolvingLoadBalancingPolicy to process a
 | 
	
		
			
				|  |  |  // resolver result update.
 | 
	
		
			
				|  |  |  bool ChannelData::ProcessResolverResultLocked(
 | 
	
		
			
				|  |  | -    void* arg, const Resolver::Result& result, const char** lb_policy_name,
 | 
	
		
			
				|  |  | +    void* arg, const Resolver::Result& result,
 | 
	
		
			
				|  |  |      RefCountedPtr<LoadBalancingPolicy::Config>* lb_policy_config,
 | 
	
		
			
				|  |  | -    grpc_error** service_config_error) {
 | 
	
		
			
				|  |  | +    grpc_error** service_config_error, bool* no_valid_service_config) {
 | 
	
		
			
				|  |  |    ChannelData* chand = static_cast<ChannelData*>(arg);
 | 
	
		
			
				|  |  |    RefCountedPtr<ServiceConfig> service_config;
 | 
	
		
			
				|  |  |    // If resolver did not return a service config or returned an invalid service
 | 
	
	
		
			
				|  | @@ -1680,13 +1697,13 @@ bool ChannelData::ProcessResolverResultLocked(
 | 
	
		
			
				|  |  |      // config. If there is no saved config either, use the default service
 | 
	
		
			
				|  |  |      // config.
 | 
	
		
			
				|  |  |      if (chand->saved_service_config_ != nullptr) {
 | 
	
		
			
				|  |  | -      service_config = chand->saved_service_config_;
 | 
	
		
			
				|  |  |        if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
 | 
	
		
			
				|  |  |          gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  |                  "chand=%p: resolver returned invalid service config. "
 | 
	
		
			
				|  |  |                  "Continuing to use previous service config.",
 | 
	
		
			
				|  |  |                  chand);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +      service_config = chand->saved_service_config_;
 | 
	
		
			
				|  |  |      } else if (chand->default_service_config_ != nullptr) {
 | 
	
		
			
				|  |  |        if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
 | 
	
		
			
				|  |  |          gpr_log(GPR_INFO,
 | 
	
	
		
			
				|  | @@ -1712,6 +1729,7 @@ bool ChannelData::ProcessResolverResultLocked(
 | 
	
		
			
				|  |  |    *service_config_error = GRPC_ERROR_REF(result.service_config_error);
 | 
	
		
			
				|  |  |    if (service_config == nullptr &&
 | 
	
		
			
				|  |  |        result.service_config_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    *no_valid_service_config = true;
 | 
	
		
			
				|  |  |      return false;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Process service config.
 | 
	
	
		
			
				|  | @@ -1776,19 +1794,18 @@ bool ChannelData::ProcessResolverResultLocked(
 | 
	
		
			
				|  |  |      chand->UpdateServiceConfigLocked(std::move(retry_throttle_data),
 | 
	
		
			
				|  |  |                                       chand->saved_service_config_);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  grpc_core::UniquePtr<char> processed_lb_policy_name;
 | 
	
		
			
				|  |  | -  chand->ProcessLbPolicy(result, parsed_service_config,
 | 
	
		
			
				|  |  | -                         &processed_lb_policy_name, lb_policy_config);
 | 
	
		
			
				|  |  | +  chand->ProcessLbPolicy(result, parsed_service_config, lb_policy_config);
 | 
	
		
			
				|  |  | +  grpc_core::UniquePtr<char> lb_policy_name(
 | 
	
		
			
				|  |  | +      gpr_strdup((*lb_policy_config)->name()));
 | 
	
		
			
				|  |  |    // Swap out the data used by GetChannelInfo().
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      MutexLock lock(&chand->info_mu_);
 | 
	
		
			
				|  |  | -    chand->info_lb_policy_name_ = std::move(processed_lb_policy_name);
 | 
	
		
			
				|  |  | +    chand->info_lb_policy_name_ = std::move(lb_policy_name);
 | 
	
		
			
				|  |  |      if (service_config_json != nullptr) {
 | 
	
		
			
				|  |  |        chand->info_service_config_json_ = std::move(service_config_json);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Return results.
 | 
	
		
			
				|  |  | -  *lb_policy_name = chand->info_lb_policy_name_.get();
 | 
	
		
			
				|  |  |    return service_config_changed;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |