Move resolver to core configuration (#28881)

* Move resolver to core configuration

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* fix

* fix

* fix

* fix

* resolver: clean up and modernize registry

* fix race

* update visibility

* fix internal error

* review feedback

* resolve backref issues

* windows

* x

* fix sockaddrs on windows?

* fix sockaddrs on windows?

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
Co-authored-by: Mark D. Roth <roth@google.com>
diff --git a/BUILD b/BUILD
index 7d79013..8a3abc9 100644
--- a/BUILD
+++ b/BUILD
@@ -970,11 +970,13 @@
     public_hdrs = [
         "src/core/lib/config/core_configuration.h",
     ],
+    visibility = ["@grpc:client_channel"],
     deps = [
         "channel_args_preconditioning",
         "channel_creds_registry",
         "channel_init",
         "gpr_base",
+        "grpc_resolver",
         "handshaker_registry",
     ],
 )
@@ -1715,6 +1717,8 @@
     name = "grpc_sockaddr",
     srcs = [
         "src/core/lib/event_engine/sockaddr.cc",
+        "src/core/lib/iomgr/sockaddr_utils_posix.cc",
+        "src/core/lib/iomgr/socket_utils_windows.cc",
     ],
     hdrs = [
         "src/core/lib/event_engine/sockaddr.h",
@@ -1724,7 +1728,7 @@
         "src/core/lib/iomgr/socket_utils.h",
     ],
     deps = [
-        "gpr_platform",
+        "gpr_base",
         "iomgr_port",
     ],
 )
@@ -1901,7 +1905,6 @@
         "src/core/lib/iomgr/socket_utils_common_posix.cc",
         "src/core/lib/iomgr/socket_utils_linux.cc",
         "src/core/lib/iomgr/socket_utils_posix.cc",
-        "src/core/lib/iomgr/socket_utils_windows.cc",
         "src/core/lib/iomgr/socket_windows.cc",
         "src/core/lib/iomgr/tcp_client.cc",
         "src/core/lib/iomgr/tcp_client_cfstream.cc",
@@ -2289,6 +2292,7 @@
         "src/core/lib/resolver/resolver_registry.h",
     ],
     external_deps = [
+        "absl/memory",
         "absl/strings",
         "absl/strings:str_format",
     ],
@@ -2731,6 +2735,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "dual_ref_counted",
         "gpr_base",
         "gpr_codegen",
@@ -3013,6 +3018,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "gpr_base",
         "grpc_base",
         "grpc_client_channel",
@@ -3369,6 +3375,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "gpr_base",
         "grpc_base",
         "grpc_client_channel",
@@ -3403,6 +3410,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "error",
         "gpr_base",
         "grpc_base",
@@ -3429,6 +3437,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "gpr_base",
         "grpc_base",
         "grpc_client_channel",
@@ -3448,6 +3457,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "gpr_base",
         "grpc_base",
         "grpc_client_channel",
@@ -3468,6 +3478,7 @@
         "@grpc:grpc_resolver_fake",
     ],
     deps = [
+        "config",
         "gpr_base",
         "grpc_base",
         "grpc_client_channel",
@@ -3498,6 +3509,7 @@
     ],
     language = "c++",
     deps = [
+        "config",
         "gpr_base",
         "grpc_base",
         "grpc_client_channel",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb163b8..0c83813 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -632,7 +632,6 @@
   add_dependencies(buildtests_c bin_encoder_test)
   add_dependencies(buildtests_c buffer_list_test)
   add_dependencies(buildtests_c channel_args_test)
-  add_dependencies(buildtests_c channel_create_test)
   add_dependencies(buildtests_c channel_stack_test)
   add_dependencies(buildtests_c check_gcp_environment_linux_test)
   add_dependencies(buildtests_c check_gcp_environment_windows_test)
@@ -2056,6 +2055,7 @@
   src/core/lib/iomgr/resolve_address.cc
   src/core/lib/iomgr/resolve_address_posix.cc
   src/core/lib/iomgr/resolve_address_windows.cc
+  src/core/lib/iomgr/sockaddr_utils_posix.cc
   src/core/lib/iomgr/socket_factory_posix.cc
   src/core/lib/iomgr/socket_mutator.cc
   src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2695,6 +2695,7 @@
   src/core/lib/iomgr/resolve_address.cc
   src/core/lib/iomgr/resolve_address_posix.cc
   src/core/lib/iomgr/resolve_address_windows.cc
+  src/core/lib/iomgr/sockaddr_utils_posix.cc
   src/core/lib/iomgr/socket_factory_posix.cc
   src/core/lib/iomgr/socket_mutator.cc
   src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -4834,33 +4835,6 @@
 endif()
 if(gRPC_BUILD_TESTS)
 
-add_executable(channel_create_test
-  test/core/surface/channel_create_test.cc
-)
-
-target_include_directories(channel_create_test
-  PRIVATE
-    ${CMAKE_CURRENT_SOURCE_DIR}
-    ${CMAKE_CURRENT_SOURCE_DIR}/include
-    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
-    ${_gRPC_RE2_INCLUDE_DIR}
-    ${_gRPC_SSL_INCLUDE_DIR}
-    ${_gRPC_UPB_GENERATED_DIR}
-    ${_gRPC_UPB_GRPC_GENERATED_DIR}
-    ${_gRPC_UPB_INCLUDE_DIR}
-    ${_gRPC_XXHASH_INCLUDE_DIR}
-    ${_gRPC_ZLIB_INCLUDE_DIR}
-)
-
-target_link_libraries(channel_create_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-)
-
-
-endif()
-if(gRPC_BUILD_TESTS)
-
 add_executable(channel_stack_test
   test/core/channel/channel_stack_test.cc
 )
@@ -9678,23 +9652,6 @@
 if(gRPC_BUILD_TESTS)
 
 add_executable(core_configuration_test
-  src/core/lib/channel/channel_args.cc
-  src/core/lib/channel/channel_args_preconditioning.cc
-  src/core/lib/channel/handshaker_registry.cc
-  src/core/lib/config/core_configuration.cc
-  src/core/lib/debug/trace.cc
-  src/core/lib/iomgr/combiner.cc
-  src/core/lib/iomgr/error.cc
-  src/core/lib/iomgr/exec_ctx.cc
-  src/core/lib/iomgr/executor.cc
-  src/core/lib/iomgr/iomgr_internal.cc
-  src/core/lib/json/json_reader.cc
-  src/core/lib/json/json_writer.cc
-  src/core/lib/slice/slice.cc
-  src/core/lib/slice/slice_refcount.cc
-  src/core/lib/slice/slice_string_helpers.cc
-  src/core/lib/surface/channel_init.cc
-  src/core/lib/surface/channel_stack_type.cc
   test/core/config/core_configuration_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
   third_party/googletest/googlemock/src/gmock-all.cc
@@ -9722,7 +9679,7 @@
 target_link_libraries(core_configuration_test
   ${_gRPC_PROTOBUF_LIBRARIES}
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr
+  grpc
 )
 
 
diff --git a/Makefile b/Makefile
index 86ea73b..a7a0be3 100644
--- a/Makefile
+++ b/Makefile
@@ -1502,6 +1502,7 @@
     src/core/lib/iomgr/resolve_address.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
+    src/core/lib/iomgr/sockaddr_utils_posix.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
@@ -1990,6 +1991,7 @@
     src/core/lib/iomgr/resolve_address.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
+    src/core/lib/iomgr/sockaddr_utils_posix.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index e7a2676..3b7c237 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -43,6 +43,13 @@
         "//conditions:default": a,
     })
 
+def if_windows(a):
+    return select({
+        "//:windows": a,
+        "//:windows_msvc": a,
+        "//conditions:default": [],
+    })
+
 def if_mac(a):
     return select({
         "//:mac_x86_64": a,
@@ -153,7 +160,7 @@
         copts = if_mac(["-DGRPC_CFSTREAM"])
     if language.upper() == "C":
         copts = copts + if_not_windows(["-std=c99"])
-    linkopts = if_not_windows(["-pthread"])
+    linkopts = if_not_windows(["-pthread"]) + if_windows(["-defaultlib:ws2_32.lib"])
     if use_cfstream:
         linkopts = linkopts + if_mac(["-framework CoreFoundation"])
 
@@ -300,7 +307,7 @@
         "data": data,
         "deps": deps + _get_external_deps(external_deps),
         "copts": GRPC_DEFAULT_COPTS + copts,
-        "linkopts": if_not_windows(["-pthread"]),
+        "linkopts": if_not_windows(["-pthread"]) + if_windows(["-defaultlib:ws2_32.lib"]),
         "size": size,
         "timeout": timeout,
         "exec_compatible_with": exec_compatible_with,
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index cfba273..1d50f80 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -1550,6 +1550,7 @@
   - src/core/lib/iomgr/resolve_address.cc
   - src/core/lib/iomgr/resolve_address_posix.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
+  - src/core/lib/iomgr/sockaddr_utils_posix.cc
   - src/core/lib/iomgr/socket_factory_posix.cc
   - src/core/lib/iomgr/socket_mutator.cc
   - src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -2366,6 +2367,7 @@
   - src/core/lib/iomgr/resolve_address.cc
   - src/core/lib/iomgr/resolve_address_posix.cc
   - src/core/lib/iomgr/resolve_address_windows.cc
+  - src/core/lib/iomgr/sockaddr_utils_posix.cc
   - src/core/lib/iomgr/socket_factory_posix.cc
   - src/core/lib/iomgr/socket_mutator.cc
   - src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -3421,14 +3423,6 @@
   deps:
   - grpc_test_util
   uses_polling: false
-- name: channel_create_test
-  build: test
-  language: c
-  headers: []
-  src:
-  - test/core/surface/channel_create_test.cc
-  deps:
-  - grpc_test_util
 - name: channel_stack_test
   build: test
   language: c
@@ -5398,53 +5392,11 @@
   gtest: true
   build: test
   language: c++
-  headers:
-  - src/core/lib/channel/channel_args.h
-  - src/core/lib/channel/channel_args_preconditioning.h
-  - src/core/lib/channel/handshaker_factory.h
-  - src/core/lib/channel/handshaker_registry.h
-  - src/core/lib/config/core_configuration.h
-  - src/core/lib/debug/trace.h
-  - src/core/lib/gprpp/atomic_utils.h
-  - src/core/lib/gprpp/ref_counted.h
-  - src/core/lib/gprpp/ref_counted_ptr.h
-  - src/core/lib/iomgr/closure.h
-  - src/core/lib/iomgr/combiner.h
-  - src/core/lib/iomgr/error.h
-  - src/core/lib/iomgr/error_internal.h
-  - src/core/lib/iomgr/exec_ctx.h
-  - src/core/lib/iomgr/executor.h
-  - src/core/lib/iomgr/iomgr_internal.h
-  - src/core/lib/json/json.h
-  - src/core/lib/security/credentials/channel_creds_registry.h
-  - src/core/lib/slice/slice.h
-  - src/core/lib/slice/slice_internal.h
-  - src/core/lib/slice/slice_refcount.h
-  - src/core/lib/slice/slice_refcount_base.h
-  - src/core/lib/slice/slice_string_helpers.h
-  - src/core/lib/surface/channel_init.h
-  - src/core/lib/surface/channel_stack_type.h
+  headers: []
   src:
-  - src/core/lib/channel/channel_args.cc
-  - src/core/lib/channel/channel_args_preconditioning.cc
-  - src/core/lib/channel/handshaker_registry.cc
-  - src/core/lib/config/core_configuration.cc
-  - src/core/lib/debug/trace.cc
-  - src/core/lib/iomgr/combiner.cc
-  - src/core/lib/iomgr/error.cc
-  - src/core/lib/iomgr/exec_ctx.cc
-  - src/core/lib/iomgr/executor.cc
-  - src/core/lib/iomgr/iomgr_internal.cc
-  - src/core/lib/json/json_reader.cc
-  - src/core/lib/json/json_writer.cc
-  - src/core/lib/slice/slice.cc
-  - src/core/lib/slice/slice_refcount.cc
-  - src/core/lib/slice/slice_string_helpers.cc
-  - src/core/lib/surface/channel_init.cc
-  - src/core/lib/surface/channel_stack_type.cc
   - test/core/config/core_configuration_test.cc
   deps:
-  - gpr
+  - grpc
   uses_polling: false
 - name: cpp_impl_of_test
   gtest: true
diff --git a/config.m4 b/config.m4
index 8b7a1a3..d285b62 100644
--- a/config.m4
+++ b/config.m4
@@ -562,6 +562,7 @@
     src/core/lib/iomgr/resolve_address.cc \
     src/core/lib/iomgr/resolve_address_posix.cc \
     src/core/lib/iomgr/resolve_address_windows.cc \
+    src/core/lib/iomgr/sockaddr_utils_posix.cc \
     src/core/lib/iomgr/socket_factory_posix.cc \
     src/core/lib/iomgr/socket_mutator.cc \
     src/core/lib/iomgr/socket_utils_common_posix.cc \
diff --git a/config.w32 b/config.w32
index 8b6d19f..4b16e5b 100644
--- a/config.w32
+++ b/config.w32
@@ -528,6 +528,7 @@
     "src\\core\\lib\\iomgr\\resolve_address.cc " +
     "src\\core\\lib\\iomgr\\resolve_address_posix.cc " +
     "src\\core\\lib\\iomgr\\resolve_address_windows.cc " +
+    "src\\core\\lib\\iomgr\\sockaddr_utils_posix.cc " +
     "src\\core\\lib\\iomgr\\socket_factory_posix.cc " +
     "src\\core\\lib\\iomgr\\socket_mutator.cc " +
     "src\\core\\lib\\iomgr\\socket_utils_common_posix.cc " +
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 928a5eb..ca77a7a 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1212,6 +1212,7 @@
                       'src/core/lib/iomgr/resolved_address.h',
                       'src/core/lib/iomgr/sockaddr.h',
                       'src/core/lib/iomgr/sockaddr_posix.h',
+                      'src/core/lib/iomgr/sockaddr_utils_posix.cc',
                       'src/core/lib/iomgr/sockaddr_windows.h',
                       'src/core/lib/iomgr/socket_factory_posix.cc',
                       'src/core/lib/iomgr/socket_factory_posix.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index f012358..0175328 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1131,6 +1131,7 @@
   s.files += %w( src/core/lib/iomgr/resolved_address.h )
   s.files += %w( src/core/lib/iomgr/sockaddr.h )
   s.files += %w( src/core/lib/iomgr/sockaddr_posix.h )
+  s.files += %w( src/core/lib/iomgr/sockaddr_utils_posix.cc )
   s.files += %w( src/core/lib/iomgr/sockaddr_windows.h )
   s.files += %w( src/core/lib/iomgr/socket_factory_posix.cc )
   s.files += %w( src/core/lib/iomgr/socket_factory_posix.h )
diff --git a/grpc.gyp b/grpc.gyp
index 450a471..0478fe3 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -956,6 +956,7 @@
         'src/core/lib/iomgr/resolve_address.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
+        'src/core/lib/iomgr/sockaddr_utils_posix.cc',
         'src/core/lib/iomgr/socket_factory_posix.cc',
         'src/core/lib/iomgr/socket_mutator.cc',
         'src/core/lib/iomgr/socket_utils_common_posix.cc',
@@ -1415,6 +1416,7 @@
         'src/core/lib/iomgr/resolve_address.cc',
         'src/core/lib/iomgr/resolve_address_posix.cc',
         'src/core/lib/iomgr/resolve_address_windows.cc',
+        'src/core/lib/iomgr/sockaddr_utils_posix.cc',
         'src/core/lib/iomgr/socket_factory_posix.cc',
         'src/core/lib/iomgr/socket_mutator.cc',
         'src/core/lib/iomgr/socket_utils_common_posix.cc',
diff --git a/package.xml b/package.xml
index 1a58c95..34bbe38 100644
--- a/package.xml
+++ b/package.xml
@@ -1111,6 +1111,7 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/resolved_address.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_posix.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_utils_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/sockaddr_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/socket_factory_posix.h" role="src" />
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index 644875f..92784da 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -1083,7 +1083,8 @@
   }
   // Make sure the URI to resolve is valid, so that we know that
   // resolver creation will succeed later.
-  if (!ResolverRegistry::IsValidTarget(uri_to_resolve_)) {
+  if (!CoreConfiguration::Get().resolver_registry().IsValidTarget(
+          uri_to_resolve_)) {
     *error = GRPC_ERROR_CREATE_FROM_CPP_STRING(
         absl::StrCat("the target uri is not valid: ", uri_to_resolve_));
     return;
@@ -1102,7 +1103,9 @@
   const char* default_authority =
       grpc_channel_args_find_string(channel_args_, GRPC_ARG_DEFAULT_AUTHORITY);
   if (default_authority == nullptr) {
-    default_authority_ = ResolverRegistry::GetDefaultAuthority(server_uri);
+    default_authority_ =
+        CoreConfiguration::Get().resolver_registry().GetDefaultAuthority(
+            server_uri);
   } else {
     default_authority_ = default_authority;
   }
@@ -1539,7 +1542,7 @@
   if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
     gpr_log(GPR_INFO, "chand=%p: starting name resolution", this);
   }
-  resolver_ = ResolverRegistry::CreateResolver(
+  resolver_ = CoreConfiguration::Get().resolver_registry().CreateResolver(
       uri_to_resolve_.c_str(), channel_args_, interested_parties_,
       work_serializer_, absl::make_unique<ResolverResultHandler>(this));
   // Since the validity of the args was checked when the channel was created,
diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.cc b/src/core/ext/filters/client_channel/client_channel_plugin.cc
index 6d77499..0f3fa83 100644
--- a/src/core/ext/filters/client_channel/client_channel_plugin.cc
+++ b/src/core/ext/filters/client_channel/client_channel_plugin.cc
@@ -42,7 +42,6 @@
   grpc_core::internal::ClientChannelServiceConfigParser::Register();
   grpc_core::internal::RetryServiceConfigParser::Register();
   grpc_core::LoadBalancingPolicyRegistry::Builder::InitRegistry();
-  grpc_core::ResolverRegistry::Builder::InitRegistry();
   grpc_core::internal::ServerRetryThrottleMap::Init();
   grpc_core::ProxyMapperRegistry::Init();
   grpc_core::RegisterHttpProxyMapper();
@@ -54,7 +53,6 @@
   grpc_core::GlobalSubchannelPool::Shutdown();
   grpc_core::ProxyMapperRegistry::Shutdown();
   grpc_core::internal::ServerRetryThrottleMap::Shutdown();
-  grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
   grpc_core::LoadBalancingPolicyRegistry::Builder::ShutdownRegistry();
 }
 
diff --git a/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc b/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc
index 08f090f..abfd560 100644
--- a/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc
@@ -55,6 +55,7 @@
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 #include "src/core/lib/backoff/backoff.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/env.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/dual_ref_counted.h"
@@ -2345,7 +2346,8 @@
   // Parse lookupService.
   if (ParseJsonObjectField(json, "lookupService",
                            &route_lookup_config.lookup_service, &error_list)) {
-    if (!ResolverRegistry::IsValidTarget(route_lookup_config.lookup_service)) {
+    if (!CoreConfiguration::Get().resolver_registry().IsValidTarget(
+            route_lookup_config.lookup_service)) {
       error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
           "field:lookupService error:must be valid gRPC target URI"));
     }
diff --git a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
index c0d806e..3e598ce 100644
--- a/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/xds/xds_cluster_resolver.cc
@@ -40,6 +40,7 @@
 #include "src/core/ext/xds/xds_client_stats.h"
 #include "src/core/ext/xds/xds_endpoint.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/orphanable.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
@@ -452,7 +453,7 @@
     target = absl::StrCat("dns:", target);
     args = grpc_channel_args_copy(parent()->args_);
   }
-  resolver_ = ResolverRegistry::CreateResolver(
+  resolver_ = CoreConfiguration::Get().resolver_registry().CreateResolver(
       target.c_str(), args, parent()->interested_parties(),
       parent()->work_serializer(),
       absl::make_unique<ResolverResultHandler>(
diff --git a/src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc b/src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
index 263164a..240394b 100644
--- a/src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
@@ -25,6 +25,7 @@
 
 #include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/resolver/resolver_registry.h"
 #include "src/core/lib/resolver/server_address.h"
@@ -59,6 +60,8 @@
 
 class BinderResolverFactory : public ResolverFactory {
  public:
+  absl::string_view scheme() const override { return "binder"; }
+
   bool IsValidUri(const URI& uri) const override {
     return ParseUri(uri, nullptr);
   }
@@ -70,8 +73,6 @@
                                           std::move(args));
   }
 
-  const char* scheme() const override { return "binder"; }
-
  private:
   static grpc_error_handle BinderAddrPopulate(
       absl::string_view path, grpc_resolved_address* resolved_addr) {
@@ -121,19 +122,12 @@
 };
 
 }  // namespace
-}  // namespace grpc_core
 
-void grpc_resolver_binder_init() {
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::BinderResolverFactory>());
+void RegisterBinderResolver(CoreConfiguration::Builder* builder) {
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<BinderResolverFactory>());
 }
 
-void grpc_resolver_binder_shutdown() {}
-
-#else
-
-void grpc_resolver_binder_init() {}
-
-void grpc_resolver_binder_shutdown() {}
+}  // namespace grpc_core
 
 #endif
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 001aaba..1413430 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -16,6 +16,8 @@
 
 #include <grpc/support/port_platform.h>
 
+#include "src/core/lib/config/core_configuration.h"
+
 #if GRPC_ARES == 1
 
 #include <limits.h>
@@ -466,6 +468,8 @@
 //
 class AresClientChannelDNSResolverFactory : public ResolverFactory {
  public:
+  absl::string_view scheme() const override { return "dns"; }
+
   bool IsValidUri(const URI& uri) const override {
     if (absl::StripPrefix(uri.path(), "/").empty()) {
       gpr_log(GPR_ERROR, "no server name supplied in dns URI");
@@ -477,8 +481,6 @@
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return MakeOrphanable<AresClientChannelDNSResolver>(std::move(args));
   }
-
-  const char* scheme() const override { return "dns"; }
 };
 
 class AresDNSResolver : public DNSResolver {
@@ -608,18 +610,29 @@
          gpr_stricmp(resolver_env, "ares") == 0;
 }
 
-bool g_use_ares_dns_resolver;
+bool UseAresDnsResolver() {
+  static const bool result = []() {
+    UniquePtr<char> resolver = GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
+    bool result = ShouldUseAres(resolver.get());
+    if (result) gpr_log(GPR_DEBUG, "Using ares dns resolver");
+    return result;
+  }();
+  return result;
+}
 
 }  // namespace
 
+void RegisterAresDnsResolver(CoreConfiguration::Builder* builder) {
+  if (UseAresDnsResolver()) {
+    builder->resolver_registry()->RegisterResolverFactory(
+        absl::make_unique<AresClientChannelDNSResolverFactory>());
+  }
+}
+
 }  // namespace grpc_core
 
 void grpc_resolver_dns_ares_init() {
-  grpc_core::UniquePtr<char> resolver =
-      GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
-  if (grpc_core::ShouldUseAres(resolver.get())) {
-    grpc_core::g_use_ares_dns_resolver = true;
-    gpr_log(GPR_DEBUG, "Using ares dns resolver");
+  if (grpc_core::UseAresDnsResolver()) {
     address_sorting_init();
     grpc_error_handle error = grpc_ares_init();
     if (error != GRPC_ERROR_NONE) {
@@ -627,15 +640,11 @@
       return;
     }
     grpc_core::SetDNSResolver(grpc_core::AresDNSResolver::GetOrCreate());
-    grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-        absl::make_unique<grpc_core::AresClientChannelDNSResolverFactory>());
-  } else {
-    grpc_core::g_use_ares_dns_resolver = false;
   }
 }
 
 void grpc_resolver_dns_ares_shutdown() {
-  if (grpc_core::g_use_ares_dns_resolver) {
+  if (grpc_core::UseAresDnsResolver()) {
     address_sorting_shutdown();
     grpc_ares_cleanup();
   }
@@ -643,8 +652,12 @@
 
 #else /* GRPC_ARES == 1 */
 
-void grpc_resolver_dns_ares_init(void) {}
+namespace grpc_core {
+void RegisterAresDnsResolver(CoreConfiguration::Builder*) {}
+}  // namespace grpc_core
 
-void grpc_resolver_dns_ares_shutdown(void) {}
+void grpc_resolver_dns_ares_init() {}
+
+void grpc_resolver_dns_ares_shutdown() {}
 
 #endif /* GRPC_ARES == 1 */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 6d3acc3..55e1476 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -31,6 +31,7 @@
 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
 #include "src/core/lib/backoff/backoff.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/manual_constructor.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -294,6 +295,8 @@
 
 class NativeClientChannelDNSResolverFactory : public ResolverFactory {
  public:
+  absl::string_view scheme() const override { return "dns"; }
+
   bool IsValidUri(const URI& uri) const override {
     if (GPR_UNLIKELY(!uri.authority().empty())) {
       gpr_log(GPR_ERROR, "authority based dns uri's not supported");
@@ -310,32 +313,24 @@
     if (!IsValidUri(args.uri)) return nullptr;
     return MakeOrphanable<NativeClientChannelDNSResolver>(std::move(args));
   }
-
-  const char* scheme() const override { return "dns"; }
 };
 
 }  // namespace
 
-}  // namespace grpc_core
-
-void grpc_resolver_dns_native_init() {
-  grpc_core::UniquePtr<char> resolver =
-      GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver);
-  if (gpr_stricmp(resolver.get(), "native") == 0) {
+void RegisterNativeDnsResolver(CoreConfiguration::Builder* builder) {
+  static const char* const resolver =
+      GPR_GLOBAL_CONFIG_GET(grpc_dns_resolver).release();
+  if (gpr_stricmp(resolver, "native") == 0) {
     gpr_log(GPR_DEBUG, "Using native dns resolver");
-    grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-        absl::make_unique<grpc_core::NativeClientChannelDNSResolverFactory>());
+    builder->resolver_registry()->RegisterResolverFactory(
+        absl::make_unique<NativeClientChannelDNSResolverFactory>());
   } else {
-    grpc_core::ResolverRegistry::Builder::InitRegistry();
-    grpc_core::ResolverFactory* existing_factory =
-        grpc_core::ResolverRegistry::LookupResolverFactory("dns");
-    if (existing_factory == nullptr) {
+    if (!builder->resolver_registry()->HasResolverFactory("dns")) {
       gpr_log(GPR_DEBUG, "Using native dns resolver");
-      grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-          absl::make_unique<
-              grpc_core::NativeClientChannelDNSResolverFactory>());
+      builder->resolver_registry()->RegisterResolverFactory(
+          absl::make_unique<NativeClientChannelDNSResolverFactory>());
     }
   }
 }
 
-void grpc_resolver_dns_native_shutdown() {}
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index ebaf478..7ea635f 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -32,6 +32,7 @@
 
 #include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gpr/useful.h"
 #include "src/core/lib/iomgr/closure.h"
@@ -359,22 +360,22 @@
 
 class FakeResolverFactory : public ResolverFactory {
  public:
+  absl::string_view scheme() const override { return "fake"; }
+
   bool IsValidUri(const URI& /*uri*/) const override { return true; }
 
   OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
     return MakeOrphanable<FakeResolver>(std::move(args));
   }
-
-  const char* scheme() const override { return "fake"; }
 };
 
 }  // namespace
 
-}  // namespace grpc_core
-
-void grpc_resolver_fake_init() {
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::FakeResolverFactory>());
+void RegisterFakeResolver(CoreConfiguration::Builder* builder) {
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<FakeResolverFactory>());
 }
 
+}  // namespace grpc_core
+
 void grpc_resolver_fake_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc b/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
index b3d07d7..2c85e6e 100644
--- a/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc
@@ -250,9 +250,10 @@
       UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP")) != nullptr ||
       UniquePtr<char>(gpr_getenv("GRPC_XDS_BOOTSTRAP_CONFIG")) != nullptr) {
     using_dns_ = true;
-    child_resolver_ = ResolverRegistry::CreateResolver(
-        absl::StrCat("dns:", name_to_resolve).c_str(), args.args,
-        args.pollset_set, work_serializer_, std::move(args.result_handler));
+    child_resolver_ =
+        CoreConfiguration::Get().resolver_registry().CreateResolver(
+            absl::StrCat("dns:", name_to_resolve).c_str(), args.args,
+            args.pollset_set, work_serializer_, std::move(args.result_handler));
     GPR_ASSERT(child_resolver_ != nullptr);
     return;
   }
@@ -266,7 +267,7 @@
     metadata_server_name_ = std::string(test_only_metadata_server_override);
   }
   // Create xds resolver.
-  child_resolver_ = ResolverRegistry::CreateResolver(
+  child_resolver_ = CoreConfiguration::Get().resolver_registry().CreateResolver(
       absl::StrCat("xds:", name_to_resolve).c_str(), args.args,
       args.pollset_set, work_serializer_, std::move(args.result_handler));
   GPR_ASSERT(child_resolver_ != nullptr);
@@ -369,6 +370,12 @@
 
 class GoogleCloud2ProdResolverFactory : public ResolverFactory {
  public:
+  // TODO(roth): Remove experimental suffix once this code is proven stable,
+  // and update the scheme in google_c2p_resolver_test.cc when doing so.
+  absl::string_view scheme() const override {
+    return "google-c2p-experimental";
+  }
+
   bool IsValidUri(const URI& uri) const override {
     if (GPR_UNLIKELY(!uri.authority().empty())) {
       gpr_log(GPR_ERROR, "google-c2p URI scheme does not support authorities");
@@ -381,19 +388,13 @@
     if (!IsValidUri(args.uri)) return nullptr;
     return MakeOrphanable<GoogleCloud2ProdResolver>(std::move(args));
   }
-
-  // TODO(roth): Remove experimental suffix once this code is proven stable,
-  // and update the scheme in google_c2p_resolver_test.cc when doing so.
-  const char* scheme() const override { return "google-c2p-experimental"; }
 };
 
 }  // namespace
 
-void GoogleCloud2ProdResolverInit() {
-  ResolverRegistry::Builder::RegisterResolverFactory(
+void RegisterCloud2ProdResolver(CoreConfiguration::Builder* builder) {
+  builder->resolver_registry()->RegisterResolverFactory(
       absl::make_unique<GoogleCloud2ProdResolverFactory>());
 }
 
-void GoogleCloud2ProdResolverShutdown() {}
-
 }  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
index 085c2b6..d893f2d 100644
--- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
@@ -1,20 +1,18 @@
-/*
- *
- * Copyright 2015-2016 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.
- *
- */
+//
+// Copyright 2015 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 <grpc/support/port_platform.h>
 
@@ -30,6 +28,7 @@
 
 #include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
@@ -127,7 +126,7 @@
     return CreateSockaddrResolver(std::move(args), grpc_parse_ipv4);
   }
 
-  const char* scheme() const override { return "ipv4"; }
+  absl::string_view scheme() const override { return "ipv4"; }
 };
 
 class IPv6ResolverFactory : public ResolverFactory {
@@ -140,7 +139,7 @@
     return CreateSockaddrResolver(std::move(args), grpc_parse_ipv6);
   }
 
-  const char* scheme() const override { return "ipv6"; }
+  absl::string_view scheme() const override { return "ipv6"; }
 };
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
@@ -158,11 +157,13 @@
     return "localhost";
   }
 
-  const char* scheme() const override { return "unix"; }
+  absl::string_view scheme() const override { return "unix"; }
 };
 
 class UnixAbstractResolverFactory : public ResolverFactory {
  public:
+  absl::string_view scheme() const override { return "unix-abstract"; }
+
   bool IsValidUri(const URI& uri) const override {
     return ParseUri(uri, grpc_parse_unix_abstract, nullptr);
   }
@@ -174,26 +175,22 @@
   std::string GetDefaultAuthority(const URI& /*uri*/) const override {
     return "localhost";
   }
-
-  const char* scheme() const override { return "unix-abstract"; }
 };
 #endif  // GRPC_HAVE_UNIX_SOCKET
 
 }  // namespace
 
-}  // namespace grpc_core
-
-void grpc_resolver_sockaddr_init() {
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::IPv4ResolverFactory>());
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::IPv6ResolverFactory>());
+void RegisterSockaddrResolver(CoreConfiguration::Builder* builder) {
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<IPv4ResolverFactory>());
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<IPv6ResolverFactory>());
 #ifdef GRPC_HAVE_UNIX_SOCKET
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::UnixResolverFactory>());
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::UnixAbstractResolverFactory>());
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<UnixResolverFactory>());
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<UnixAbstractResolverFactory>());
 #endif
 }
 
-void grpc_resolver_sockaddr_shutdown() {}
+}  // namespace grpc_core
diff --git a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
index e220a77..0c3f82b 100644
--- a/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
@@ -35,6 +35,7 @@
 #include "src/core/ext/xds/xds_route_config.h"
 #include "src/core/ext/xds/xds_routing.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/iomgr/closure.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/resolver/resolver_registry.h"
@@ -988,6 +989,8 @@
 
 class XdsResolverFactory : public ResolverFactory {
  public:
+  absl::string_view scheme() const override { return "xds"; }
+
   bool IsValidUri(const URI& uri) const override {
     if (uri.path().empty() || uri.path().back() == '/') {
       gpr_log(GPR_ERROR,
@@ -1005,17 +1008,13 @@
     if (!IsValidUri(args.uri)) return nullptr;
     return MakeOrphanable<XdsResolver>(std::move(args));
   }
-
-  const char* scheme() const override { return "xds"; }
 };
 
 }  // namespace
 
-}  // namespace grpc_core
-
-void grpc_resolver_xds_init() {
-  grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
-      absl::make_unique<grpc_core::XdsResolverFactory>());
+void RegisterXdsResolver(CoreConfiguration::Builder* builder) {
+  builder->resolver_registry()->RegisterResolverFactory(
+      absl::make_unique<XdsResolverFactory>());
 }
 
-void grpc_resolver_xds_shutdown() {}
+}  // namespace grpc_core
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.cc b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
index 46c4f37..fc15031 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.cc
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.cc
@@ -353,10 +353,12 @@
     return nullptr;
   }
   // Add channel arg containing the server URI.
-  UniquePtr<char> canonical_target =
-      ResolverRegistry::AddDefaultPrefixIfNeeded(target);
+  std::string canonical_target =
+      CoreConfiguration::Get().resolver_registry().AddDefaultPrefixIfNeeded(
+          target);
   grpc_arg arg = grpc_channel_arg_string_create(
-      const_cast<char*>(GRPC_ARG_SERVER_URI), canonical_target.get());
+      const_cast<char*>(GRPC_ARG_SERVER_URI),
+      const_cast<char*>(canonical_target.c_str()));
   const char* to_remove[] = {GRPC_ARG_SERVER_URI};
   grpc_channel_args* new_args =
       grpc_channel_args_copy_and_add_and_remove(args, to_remove, 1, &arg, 1);
diff --git a/src/core/lib/config/core_configuration.cc b/src/core/lib/config/core_configuration.cc
index 8fe32b3..aeabbc2 100644
--- a/src/core/lib/config/core_configuration.cc
+++ b/src/core/lib/config/core_configuration.cc
@@ -23,6 +23,7 @@
 std::atomic<CoreConfiguration*> CoreConfiguration::config_{nullptr};
 std::atomic<CoreConfiguration::RegisteredBuilder*> CoreConfiguration::builders_{
     nullptr};
+void (*CoreConfiguration::default_builder_)(CoreConfiguration::Builder*);
 
 CoreConfiguration::Builder::Builder() = default;
 
@@ -35,7 +36,8 @@
           builder->channel_args_preconditioning_.Build()),
       channel_init_(builder->channel_init_.Build()),
       handshaker_registry_(builder->handshaker_registry_.Build()),
-      channel_creds_registry_(builder->channel_creds_registry_.Build()) {}
+      channel_creds_registry_(builder->channel_creds_registry_.Build()),
+      resolver_registry_(builder->resolver_registry_.Build()) {}
 
 void CoreConfiguration::RegisterBuilder(std::function<void(Builder*)> builder) {
   GPR_ASSERT(config_.load(std::memory_order_relaxed) == nullptr &&
@@ -70,7 +72,7 @@
     (*it)->builder(&builder);
   }
   // Finally, call the built in configuration builder.
-  BuildCoreConfiguration(&builder);
+  if (default_builder_ != nullptr) (*default_builder_)(&builder);
   // Use builder to construct a confguration
   CoreConfiguration* p = builder.Build();
   // Try to set configuration global - it's possible another thread raced us
diff --git a/src/core/lib/config/core_configuration.h b/src/core/lib/config/core_configuration.h
index df32915..e380205 100644
--- a/src/core/lib/config/core_configuration.h
+++ b/src/core/lib/config/core_configuration.h
@@ -21,6 +21,7 @@
 
 #include "src/core/lib/channel/channel_args_preconditioning.h"
 #include "src/core/lib/channel/handshaker_registry.h"
+#include "src/core/lib/resolver/resolver_registry.h"
 #include "src/core/lib/security/credentials/channel_creds_registry.h"
 #include "src/core/lib/surface/channel_init.h"
 
@@ -51,6 +52,10 @@
       return &channel_creds_registry_;
     }
 
+    ResolverRegistry::Builder* resolver_registry() {
+      return &resolver_registry_;
+    }
+
    private:
     friend class CoreConfiguration;
 
@@ -58,6 +63,7 @@
     ChannelInit::Builder channel_init_;
     HandshakerRegistry::Builder handshaker_registry_;
     ChannelCredsRegistry<>::Builder channel_creds_registry_;
+    ResolverRegistry::Builder resolver_registry_;
 
     Builder();
     CoreConfiguration* Build();
@@ -137,6 +143,14 @@
     return channel_creds_registry_;
   }
 
+  const ResolverRegistry& resolver_registry() const {
+    return resolver_registry_;
+  }
+
+  static void SetDefaultBuilder(void (*builder)(CoreConfiguration::Builder*)) {
+    default_builder_ = builder;
+  }
+
  private:
   explicit CoreConfiguration(Builder* builder);
 
@@ -154,11 +168,14 @@
   static std::atomic<CoreConfiguration*> config_;
   // Extra registered builders
   static std::atomic<RegisteredBuilder*> builders_;
+  // Default builder
+  static void (*default_builder_)(CoreConfiguration::Builder*);
 
   ChannelArgsPreconditioning channel_args_preconditioning_;
   ChannelInit channel_init_;
   HandshakerRegistry handshaker_registry_;
   ChannelCredsRegistry<> channel_creds_registry_;
+  ResolverRegistry resolver_registry_;
 };
 
 extern void BuildCoreConfiguration(CoreConfiguration::Builder* builder);
diff --git a/src/core/lib/iomgr/sockaddr_utils_posix.cc b/src/core/lib/iomgr/sockaddr_utils_posix.cc
new file mode 100644
index 0000000..ba9a6c7
--- /dev/null
+++ b/src/core/lib/iomgr/sockaddr_utils_posix.cc
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2015 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 <grpc/support/port_platform.h>
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_POSIX_SOCKET_UTILS_COMMON
+
+#include "src/core/lib/iomgr/socket_utils.h"
+#ifdef GRPC_LINUX_TCP_H
+#include <linux/tcp.h>
+#else
+#include <netinet/tcp.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/iomgr/sockaddr.h"
+
+uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
+
+uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
+
+uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
+
+uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
+
+int grpc_inet_pton(int af, const char* src, void* dst) {
+  return inet_pton(af, src, dst);
+}
+
+const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
+  GPR_ASSERT(size <= (socklen_t)-1);
+  return inet_ntop(af, src, dst, static_cast<socklen_t>(size));
+}
+
+#endif
diff --git a/src/core/lib/iomgr/socket_utils_common_posix.cc b/src/core/lib/iomgr/socket_utils_common_posix.cc
index 7c6706b..75e837b 100644
--- a/src/core/lib/iomgr/socket_utils_common_posix.cc
+++ b/src/core/lib/iomgr/socket_utils_common_posix.cc
@@ -495,21 +495,4 @@
   return error_for_fd(*newfd, resolved_addr);
 }
 
-uint16_t grpc_htons(uint16_t hostshort) { return htons(hostshort); }
-
-uint16_t grpc_ntohs(uint16_t netshort) { return ntohs(netshort); }
-
-uint32_t grpc_htonl(uint32_t hostlong) { return htonl(hostlong); }
-
-uint32_t grpc_ntohl(uint32_t netlong) { return ntohl(netlong); }
-
-int grpc_inet_pton(int af, const char* src, void* dst) {
-  return inet_pton(af, src, dst);
-}
-
-const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size) {
-  GPR_ASSERT(size <= (socklen_t)-1);
-  return inet_ntop(af, src, dst, static_cast<socklen_t>(size));
-}
-
 #endif
diff --git a/src/core/lib/resolver/resolver_factory.h b/src/core/lib/resolver/resolver_factory.h
index ccfee57..091d30e 100644
--- a/src/core/lib/resolver/resolver_factory.h
+++ b/src/core/lib/resolver/resolver_factory.h
@@ -1,20 +1,18 @@
-/*
- *
- * Copyright 2015 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.
- *
- */
+//
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #ifndef GRPC_CORE_LIB_RESOLVER_RESOLVER_FACTORY_H
 #define GRPC_CORE_LIB_RESOLVER_RESOLVER_FACTORY_H
@@ -41,8 +39,6 @@
 struct ResolverArgs {
   /// The parsed URI to resolve.
   URI uri;
-  /// The URI string.
-  std::string uri_string;
   /// Channel args to be included in resolver results.
   const grpc_channel_args* args = nullptr;
   /// Used to drive I/O in the name resolution process.
@@ -55,6 +51,12 @@
 
 class ResolverFactory {
  public:
+  virtual ~ResolverFactory() {}
+
+  /// Returns the URI scheme that this factory implements.
+  /// Caller does NOT take ownership of result.
+  virtual absl::string_view scheme() const = 0;
+
   /// Returns a bool indicating whether the input uri is valid to create a
   /// resolver.
   virtual bool IsValidUri(const URI& uri) const = 0;
@@ -67,14 +69,8 @@
   virtual std::string GetDefaultAuthority(const URI& uri) const {
     return std::string(absl::StripPrefix(uri.path(), "/"));
   }
-
-  /// Returns the URI scheme that this factory implements.
-  /// Caller does NOT take ownership of result.
-  virtual const char* scheme() const = 0;
-
-  virtual ~ResolverFactory() {}
 };
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_LIB_RESOLVER_RESOLVER_FACTORY_H */
+#endif  // GRPC_CORE_LIB_RESOLVER_RESOLVER_FACTORY_H
diff --git a/src/core/lib/resolver/resolver_registry.cc b/src/core/lib/resolver/resolver_registry.cc
index d563d28..8333bfd 100644
--- a/src/core/lib/resolver/resolver_registry.cc
+++ b/src/core/lib/resolver/resolver_registry.cc
@@ -1,20 +1,18 @@
-/*
- *
- * Copyright 2015 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.
- *
- */
+//
+// Copyright 2015 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 <grpc/support/port_platform.h>
 
@@ -24,6 +22,7 @@
 
 #include <vector>
 
+#include "absl/memory/memory.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 
@@ -31,139 +30,63 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#include "src/core/lib/resolver/resolver_registry.h"
+
 namespace grpc_core {
 
-namespace {
-
-class RegistryState {
- public:
-  RegistryState() : default_prefix_(gpr_strdup("dns:///")) {}
-
-  void SetDefaultPrefix(const char* default_resolver_prefix) {
-    GPR_ASSERT(default_resolver_prefix != nullptr);
-    GPR_ASSERT(*default_resolver_prefix != '\0');
-    default_prefix_.reset(gpr_strdup(default_resolver_prefix));
-  }
-
-  void RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory) {
-    for (size_t i = 0; i < factories_.size(); ++i) {
-      GPR_ASSERT(strcmp(factories_[i]->scheme(), factory->scheme()) != 0);
-    }
-    factories_.push_back(std::move(factory));
-  }
-
-  ResolverFactory* LookupResolverFactory(absl::string_view scheme) const {
-    for (size_t i = 0; i < factories_.size(); ++i) {
-      if (scheme == factories_[i]->scheme()) {
-        return factories_[i].get();
-      }
-    }
-    return nullptr;
-  }
-
-  // Returns the factory for the scheme of \a target.  If \a target does
-  // not parse as a URI, prepends \a default_prefix_ and tries again.
-  // If URI parsing is successful (in either attempt), sets \a uri to
-  // point to the parsed URI.
-  // If \a default_prefix_ needs to be prepended, sets \a canonical_target
-  // to the canonical target string.
-  ResolverFactory* FindResolverFactory(absl::string_view target, URI* uri,
-                                       std::string* canonical_target) const {
-    GPR_ASSERT(uri != nullptr);
-    absl::StatusOr<URI> tmp_uri = URI::Parse(target);
-    ResolverFactory* factory =
-        tmp_uri.ok() ? LookupResolverFactory(tmp_uri->scheme()) : nullptr;
-    if (factory != nullptr) {
-      *uri = std::move(*tmp_uri);
-      return factory;
-    }
-    *canonical_target = absl::StrCat(default_prefix_.get(), target);
-    absl::StatusOr<URI> tmp_uri2 = URI::Parse(*canonical_target);
-    factory =
-        tmp_uri2.ok() ? LookupResolverFactory(tmp_uri2->scheme()) : nullptr;
-    if (factory != nullptr) {
-      *uri = std::move(*tmp_uri2);
-      return factory;
-    }
-    if (!tmp_uri.ok() || !tmp_uri2.ok()) {
-      gpr_log(GPR_ERROR, "%s",
-              absl::StrFormat("Error parsing URI(s). '%s':%s; '%s':%s", target,
-                              tmp_uri.status().ToString(), *canonical_target,
-                              tmp_uri2.status().ToString())
-                  .c_str());
-      return nullptr;
-    }
-    gpr_log(GPR_ERROR, "Don't know how to resolve '%s' or '%s'.",
-            std::string(target).c_str(), canonical_target->c_str());
-    return nullptr;
-  }
-
- private:
-  // We currently support 10 factories without doing additional
-  // allocation.  This number could be raised if there is a case where
-  // more factories are needed and the additional allocations are
-  // hurting performance (which is unlikely, since these allocations
-  // only occur at gRPC initialization time).
-  absl::InlinedVector<std::unique_ptr<ResolverFactory>, 10> factories_;
-  UniquePtr<char> default_prefix_;
-};
-
-RegistryState* g_state = nullptr;
-
-}  // namespace
-
 //
 // ResolverRegistry::Builder
 //
 
-void ResolverRegistry::Builder::InitRegistry() {
-  if (g_state == nullptr) g_state = new RegistryState();
-}
+ResolverRegistry::Builder::Builder() { Reset(); }
 
-void ResolverRegistry::Builder::ShutdownRegistry() {
-  delete g_state;
-  g_state = nullptr;
-}
-
-void ResolverRegistry::Builder::SetDefaultPrefix(const char* default_prefix) {
-  InitRegistry();
-  g_state->SetDefaultPrefix(default_prefix);
+void ResolverRegistry::Builder::SetDefaultPrefix(std::string default_prefix) {
+  state_.default_prefix = std::move(default_prefix);
 }
 
 void ResolverRegistry::Builder::RegisterResolverFactory(
     std::unique_ptr<ResolverFactory> factory) {
-  InitRegistry();
-  g_state->RegisterResolverFactory(std::move(factory));
+  auto p = state_.factories.emplace(factory->scheme(), std::move(factory));
+  GPR_ASSERT(p.second);
+}
+
+bool ResolverRegistry::Builder::HasResolverFactory(
+    absl::string_view scheme) const {
+  return state_.factories.find(scheme) != state_.factories.end();
+}
+
+void ResolverRegistry::Builder::Reset() {
+  state_.factories.clear();
+  state_.default_prefix = "dns:///";
+}
+
+ResolverRegistry ResolverRegistry::Builder::Build() {
+  return ResolverRegistry(std::move(state_));
 }
 
 //
 // ResolverRegistry
 //
 
-ResolverFactory* ResolverRegistry::LookupResolverFactory(const char* scheme) {
-  GPR_ASSERT(g_state != nullptr);
-  return g_state->LookupResolverFactory(scheme);
-}
-
-bool ResolverRegistry::IsValidTarget(absl::string_view target) {
-  URI uri;
+bool ResolverRegistry::IsValidTarget(absl::string_view target) const {
   std::string canonical_target;
+  URI uri;
   ResolverFactory* factory =
-      g_state->FindResolverFactory(target, &uri, &canonical_target);
-  return factory == nullptr ? false : factory->IsValidUri(uri);
+      FindResolverFactory(target, &uri, &canonical_target);
+  if (factory == nullptr) return false;
+  return factory->IsValidUri(uri);
 }
 
 OrphanablePtr<Resolver> ResolverRegistry::CreateResolver(
-    const char* target, const grpc_channel_args* args,
+    absl::string_view target, const grpc_channel_args* args,
     grpc_pollset_set* pollset_set,
     std::shared_ptr<WorkSerializer> work_serializer,
-    std::unique_ptr<Resolver::ResultHandler> result_handler) {
-  GPR_ASSERT(g_state != nullptr);
+    std::unique_ptr<Resolver::ResultHandler> result_handler) const {
+  std::string canonical_target;
   ResolverArgs resolver_args;
-  ResolverFactory* factory = g_state->FindResolverFactory(
-      target, &resolver_args.uri, &resolver_args.uri_string);
+  ResolverFactory* factory =
+      FindResolverFactory(target, &resolver_args.uri, &canonical_target);
   if (factory == nullptr) return nullptr;
-  if (resolver_args.uri_string.empty()) resolver_args.uri_string = target;
   resolver_args.args = args;
   resolver_args.pollset_set = pollset_set;
   resolver_args.work_serializer = std::move(work_serializer);
@@ -171,25 +94,63 @@
   return factory->CreateResolver(std::move(resolver_args));
 }
 
-std::string ResolverRegistry::GetDefaultAuthority(absl::string_view target) {
-  GPR_ASSERT(g_state != nullptr);
-  URI uri;
+std::string ResolverRegistry::GetDefaultAuthority(
+    absl::string_view target) const {
   std::string canonical_target;
+  URI uri;
   ResolverFactory* factory =
-      g_state->FindResolverFactory(target, &uri, &canonical_target);
-  std::string authority =
-      factory == nullptr ? "" : factory->GetDefaultAuthority(uri);
-  return authority;
+      FindResolverFactory(target, &uri, &canonical_target);
+  if (factory == nullptr) return "";
+  return factory->GetDefaultAuthority(uri);
 }
 
-UniquePtr<char> ResolverRegistry::AddDefaultPrefixIfNeeded(const char* target) {
-  GPR_ASSERT(g_state != nullptr);
-  URI uri;
+std::string ResolverRegistry::AddDefaultPrefixIfNeeded(
+    absl::string_view target) const {
   std::string canonical_target;
-  g_state->FindResolverFactory(target, &uri, &canonical_target);
-  return UniquePtr<char>(canonical_target.empty()
-                             ? gpr_strdup(target)
-                             : gpr_strdup(canonical_target.c_str()));
+  URI uri;
+  FindResolverFactory(target, &uri, &canonical_target);
+  return canonical_target.empty() ? std::string(target) : canonical_target;
+}
+
+ResolverFactory* ResolverRegistry::LookupResolverFactory(
+    absl::string_view scheme) const {
+  auto it = state_.factories.find(scheme);
+  if (it == state_.factories.end()) return nullptr;
+  return it->second.get();
+}
+
+// Returns the factory for the scheme of \a target.  If \a target does
+// not parse as a URI, prepends \a default_prefix_ and tries again.
+// If URI parsing is successful (in either attempt), sets \a uri to
+// point to the parsed URI.
+ResolverFactory* ResolverRegistry::FindResolverFactory(
+    absl::string_view target, URI* uri, std::string* canonical_target) const {
+  GPR_ASSERT(uri != nullptr);
+  absl::StatusOr<URI> tmp_uri = URI::Parse(target);
+  ResolverFactory* factory =
+      tmp_uri.ok() ? LookupResolverFactory(tmp_uri->scheme()) : nullptr;
+  if (factory != nullptr) {
+    *uri = std::move(*tmp_uri);
+    return factory;
+  }
+  *canonical_target = absl::StrCat(state_.default_prefix, target);
+  absl::StatusOr<URI> tmp_uri2 = URI::Parse(*canonical_target);
+  factory = tmp_uri2.ok() ? LookupResolverFactory(tmp_uri2->scheme()) : nullptr;
+  if (factory != nullptr) {
+    *uri = std::move(*tmp_uri2);
+    return factory;
+  }
+  if (!tmp_uri.ok() || !tmp_uri2.ok()) {
+    gpr_log(GPR_ERROR, "%s",
+            absl::StrFormat("Error parsing URI(s). '%s':%s; '%s':%s", target,
+                            tmp_uri.status().ToString(), *canonical_target,
+                            tmp_uri2.status().ToString())
+                .c_str());
+    return nullptr;
+  }
+  gpr_log(GPR_ERROR, "Don't know how to resolve '%s' or '%s'.",
+          std::string(target).c_str(), canonical_target->c_str());
+  return nullptr;
 }
 
 }  // namespace grpc_core
diff --git a/src/core/lib/resolver/resolver_registry.h b/src/core/lib/resolver/resolver_registry.h
index c6a0361..ab96aae 100644
--- a/src/core/lib/resolver/resolver_registry.h
+++ b/src/core/lib/resolver/resolver_registry.h
@@ -1,20 +1,18 @@
-/*
- *
- * Copyright 2015 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.
- *
- */
+//
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
 
 #ifndef GRPC_CORE_LIB_RESOLVER_RESOLVER_REGISTRY_H
 #define GRPC_CORE_LIB_RESOLVER_RESOLVER_REGISTRY_H
@@ -28,29 +26,47 @@
 namespace grpc_core {
 
 class ResolverRegistry {
+ private:
+  // Forward declaration needed to use this in Builder.
+  struct State {
+    std::map<absl::string_view, std::unique_ptr<ResolverFactory>> factories;
+    std::string default_prefix;
+  };
+
  public:
   /// Methods used to create and populate the ResolverRegistry.
   /// NOT THREAD SAFE -- to be used only during global gRPC
   /// initialization and shutdown.
   class Builder {
    public:
-    /// Global initialization and shutdown hooks.
-    static void InitRegistry();
-    static void ShutdownRegistry();
+    Builder();
 
     /// Sets the default URI prefix to \a default_prefix.
-    /// Calls InitRegistry() if it has not already been called.
-    static void SetDefaultPrefix(const char* default_prefix);
+    void SetDefaultPrefix(std::string default_prefix);
 
     /// Registers a resolver factory.  The factory will be used to create a
     /// resolver for any URI whose scheme matches that of the factory.
-    /// Calls InitRegistry() if it has not already been called.
-    static void RegisterResolverFactory(
-        std::unique_ptr<ResolverFactory> factory);
+    void RegisterResolverFactory(std::unique_ptr<ResolverFactory> factory);
+
+    /// Returns true iff scheme already has a registered factory.
+    bool HasResolverFactory(absl::string_view scheme) const;
+
+    /// Wipe everything in the registry and reset to empty.
+    void Reset();
+
+    ResolverRegistry Build();
+
+   private:
+    ResolverRegistry::State state_;
   };
 
+  ResolverRegistry(const ResolverRegistry&) = delete;
+  ResolverRegistry& operator=(const ResolverRegistry&) = delete;
+  ResolverRegistry(ResolverRegistry&&) noexcept;
+  ResolverRegistry& operator=(ResolverRegistry&&) noexcept;
+
   /// Checks whether the user input \a target is valid to create a resolver.
-  static bool IsValidTarget(absl::string_view target);
+  bool IsValidTarget(absl::string_view target) const;
 
   /// Creates a resolver given \a target.
   /// First tries to parse \a target as a URI. If this succeeds, tries
@@ -65,23 +81,33 @@
   /// name resolution process. \a work_serializer is the work_serializer under
   /// which all resolver calls will be run. \a result_handler is used to return
   /// results from the resolver.
-  static OrphanablePtr<Resolver> CreateResolver(
-      const char* target, const grpc_channel_args* args,
+  OrphanablePtr<Resolver> CreateResolver(
+      absl::string_view target, const grpc_channel_args* args,
       grpc_pollset_set* pollset_set,
       std::shared_ptr<WorkSerializer> work_serializer,
-      std::unique_ptr<Resolver::ResultHandler> result_handler);
+      std::unique_ptr<Resolver::ResultHandler> result_handler) const;
 
   /// Returns the default authority to pass from a client for \a target.
-  static std::string GetDefaultAuthority(absl::string_view target);
+  std::string GetDefaultAuthority(absl::string_view target) const;
 
   /// Returns \a target with the default prefix prepended, if needed.
-  static UniquePtr<char> AddDefaultPrefixIfNeeded(const char* target);
+  std::string AddDefaultPrefixIfNeeded(absl::string_view target) const;
 
   /// Returns the resolver factory for \a scheme.
   /// Caller does NOT own the return value.
-  static ResolverFactory* LookupResolverFactory(const char* scheme);
+  ResolverFactory* LookupResolverFactory(absl::string_view scheme) const;
+
+ private:
+  explicit ResolverRegistry(State state) : state_(std::move(state)) {}
+
+  // TODO(ctiller): fix callers such that the canonical_target argument can be
+  // removed, and replaced with uri.ToString().
+  ResolverFactory* FindResolverFactory(absl::string_view target, URI* uri,
+                                       std::string* canonical_target) const;
+
+  State state_;
 };
 
 }  // namespace grpc_core
 
-#endif /* GRPC_CORE_LIB_RESOLVER_RESOLVER_REGISTRY_H */
+#endif  // GRPC_CORE_LIB_RESOLVER_RESOLVER_REGISTRY_H
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index e4bf4f9..c979b98 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -72,7 +72,11 @@
 
 static gpr_once g_basic_init = GPR_ONCE_INIT;
 static grpc_core::Mutex* g_init_mu;
-static int g_initializations ABSL_GUARDED_BY(g_init_mu) = 0;
+static int g_initializations ABSL_GUARDED_BY(g_init_mu) = []() {
+  grpc_core::CoreConfiguration::SetDefaultBuilder(
+      grpc_core::BuildCoreConfiguration);
+  return 0;
+}();
 static grpc_core::CondVar* g_shutting_down_cv;
 static bool g_shutting_down ABSL_GUARDED_BY(g_init_mu) = false;
 
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index 806ba27..a3c35c0 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -29,8 +29,6 @@
 void grpc_chttp2_plugin_shutdown(void);
 void grpc_client_channel_init(void);
 void grpc_client_channel_shutdown(void);
-void grpc_resolver_fake_init(void);
-void grpc_resolver_fake_shutdown(void);
 void grpc_lb_policy_grpclb_init(void);
 void grpc_lb_policy_grpclb_shutdown(void);
 void grpc_lb_policy_priority_init(void);
@@ -43,10 +41,6 @@
 void grpc_lb_policy_round_robin_shutdown(void);
 void grpc_resolver_dns_ares_init(void);
 void grpc_resolver_dns_ares_shutdown(void);
-void grpc_resolver_dns_native_init(void);
-void grpc_resolver_dns_native_shutdown(void);
-void grpc_resolver_sockaddr_init(void);
-void grpc_resolver_sockaddr_shutdown(void);
 void grpc_message_size_filter_init(void);
 void grpc_message_size_filter_shutdown(void);
 namespace grpc_core {
@@ -62,16 +56,10 @@
 void ServiceConfigParserShutdown(void);
 }  // namespace grpc_core
 
-#ifdef GPR_SUPPORT_BINDER_TRANSPORT
-void grpc_resolver_binder_init(void);
-void grpc_resolver_binder_shutdown(void);
-#endif
-
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_core::ServiceConfigParserInit,
                        grpc_core::ServiceConfigParserShutdown);
   grpc_register_plugin(grpc_client_channel_init, grpc_client_channel_shutdown);
-  grpc_register_plugin(grpc_resolver_fake_init, grpc_resolver_fake_shutdown);
   grpc_register_plugin(grpc_lb_policy_grpclb_init,
                        grpc_lb_policy_grpclb_shutdown);
 #ifndef GRPC_NO_RLS
@@ -90,18 +78,10 @@
                        grpc_core::GrpcLbPolicyRingHashShutdown);
   grpc_register_plugin(grpc_resolver_dns_ares_init,
                        grpc_resolver_dns_ares_shutdown);
-  grpc_register_plugin(grpc_resolver_dns_native_init,
-                       grpc_resolver_dns_native_shutdown);
-  grpc_register_plugin(grpc_resolver_sockaddr_init,
-                       grpc_resolver_sockaddr_shutdown);
   grpc_register_plugin(grpc_message_size_filter_init,
                        grpc_message_size_filter_shutdown);
   grpc_register_plugin(grpc_core::FaultInjectionFilterInit,
                        grpc_core::FaultInjectionFilterShutdown);
-#ifdef GPR_SUPPORT_BINDER_TRANSPORT
-  grpc_register_plugin(grpc_resolver_binder_init,
-                       grpc_resolver_binder_shutdown);
-#endif
   grpc_register_extra_plugins();
 }
 
@@ -124,6 +104,13 @@
     CoreConfiguration::Builder* builder);
 extern void RegisterExtraFilters(CoreConfiguration::Builder* builder);
 extern void RegisterResourceQuota(CoreConfiguration::Builder* builder);
+extern void RegisterNativeDnsResolver(CoreConfiguration::Builder* builder);
+extern void RegisterAresDnsResolver(CoreConfiguration::Builder* builder);
+extern void RegisterSockaddrResolver(CoreConfiguration::Builder* builder);
+extern void RegisterFakeResolver(CoreConfiguration::Builder* builder);
+#ifdef GPR_SUPPORT_BINDER_TRANSPORT
+extern void RegisterBinderResolver(CoreConfiguration::Builder* builder);
+#endif
 
 void BuildCoreConfiguration(CoreConfiguration::Builder* builder) {
   BuildClientChannelConfiguration(builder);
@@ -137,6 +124,13 @@
   RegisterMessageSizeFilter(builder);
   RegisterServiceConfigChannelArgFilter(builder);
   RegisterResourceQuota(builder);
+  RegisterAresDnsResolver(builder);
+  RegisterNativeDnsResolver(builder);
+  RegisterSockaddrResolver(builder);
+  RegisterFakeResolver(builder);
+#ifdef GPR_SUPPORT_BINDER_TRANSPORT
+  RegisterBinderResolver(builder);
+#endif
   // Run last so it gets a consistent location.
   // TODO(ctiller): Is this actually necessary?
   RegisterSecurityFilters(builder);
diff --git a/src/core/plugin_registry/grpc_plugin_registry_extra.cc b/src/core/plugin_registry/grpc_plugin_registry_extra.cc
index 1d5adf9..87c0929 100644
--- a/src/core/plugin_registry/grpc_plugin_registry_extra.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry_extra.cc
@@ -42,18 +42,14 @@
 void grpc_lb_policy_xds_cluster_resolver_shutdown(void);
 void grpc_lb_policy_xds_cluster_manager_init(void);
 void grpc_lb_policy_xds_cluster_manager_shutdown(void);
-void grpc_resolver_xds_init(void);
-void grpc_resolver_xds_shutdown(void);
-namespace grpc_core {
-void GoogleCloud2ProdResolverInit();
-void GoogleCloud2ProdResolverShutdown();
-}  // namespace grpc_core
 #endif
 
 void grpc_register_extra_plugins() {
 #ifndef GRPC_NO_XDS
-  // rbac_filter is being guarded with GRPC_NO_XDS to avoid a dependency on the re2 library by default
-  grpc_register_plugin(grpc_core::RbacFilterInit, grpc_core::RbacFilterShutdown);
+  // rbac_filter is being guarded with GRPC_NO_XDS to avoid a dependency on the
+  // re2 library by default
+  grpc_register_plugin(grpc_core::RbacFilterInit,
+                       grpc_core::RbacFilterShutdown);
   grpc_register_plugin(grpc_core::XdsClientGlobalInit,
                        grpc_core::XdsClientGlobalShutdown);
   grpc_register_plugin(grpc_certificate_provider_registry_init,
@@ -67,9 +63,6 @@
                        grpc_lb_policy_xds_cluster_resolver_shutdown);
   grpc_register_plugin(grpc_lb_policy_xds_cluster_manager_init,
                        grpc_lb_policy_xds_cluster_manager_shutdown);
-  grpc_register_plugin(grpc_resolver_xds_init, grpc_resolver_xds_shutdown);
-  grpc_register_plugin(grpc_core::GoogleCloud2ProdResolverInit,
-                       grpc_core::GoogleCloud2ProdResolverShutdown);
 #endif
 }
 
@@ -78,6 +71,8 @@
 extern void RegisterXdsChannelStackModifier(
     CoreConfiguration::Builder* builder);
 extern void RegisterChannelDefaultCreds(CoreConfiguration::Builder* builder);
+extern void RegisterXdsResolver(CoreConfiguration::Builder* builder);
+extern void RegisterCloud2ProdResolver(CoreConfiguration::Builder* builder);
 #endif
 void RegisterExtraFilters(CoreConfiguration::Builder* builder) {
   // Use builder to avoid unused-parameter warning.
@@ -85,7 +80,8 @@
 #ifndef GRPC_NO_XDS
   RegisterXdsChannelStackModifier(builder);
   RegisterChannelDefaultCreds(builder);
+  RegisterXdsResolver(builder);
+  RegisterCloud2ProdResolver(builder);
 #endif
 }
 }  // namespace grpc_core
-
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index d0701ba..ca8cf57 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -537,6 +537,7 @@
     'src/core/lib/iomgr/resolve_address.cc',
     'src/core/lib/iomgr/resolve_address_posix.cc',
     'src/core/lib/iomgr/resolve_address_windows.cc',
+    'src/core/lib/iomgr/sockaddr_utils_posix.cc',
     'src/core/lib/iomgr/socket_factory_posix.cc',
     'src/core/lib/iomgr/socket_mutator.cc',
     'src/core/lib/iomgr/socket_utils_common_posix.cc',
diff --git a/test/core/client_channel/resolvers/binder_resolver_test.cc b/test/core/client_channel/resolvers/binder_resolver_test.cc
index 3e7ddc2..e8bc1f8 100644
--- a/test/core/client_channel/resolvers/binder_resolver_test.cc
+++ b/test/core/client_channel/resolvers/binder_resolver_test.cc
@@ -14,6 +14,7 @@
 
 #include <gtest/gtest.h>
 
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/iomgr/port.h"
 #include "test/core/util/test_config.h"
 
@@ -34,25 +35,38 @@
 
 // Registers the factory with `grpc_core::ResolverRegistry`. Defined in
 // binder_resolver.cc
-void grpc_resolver_binder_init(void);
+namespace grpc_core {
+void RegisterBinderResolver(CoreConfiguration::Builder* builder);
+}
 
 namespace {
 
 class BinderResolverTest : public ::testing::Test {
  public:
   BinderResolverTest() {
-    factory_ = grpc_core::ResolverRegistry::LookupResolverFactory("binder");
+    factory_ = grpc_core::CoreConfiguration::Get()
+                   .resolver_registry()
+                   .LookupResolverFactory("binder");
   }
   ~BinderResolverTest() override {}
   static void SetUpTestSuite() {
+    grpc_core::CoreConfiguration::Reset();
+    grpc_core::CoreConfiguration::BuildSpecialConfiguration(
+        [](grpc_core::CoreConfiguration::Builder* builder) {
+          BuildCoreConfiguration(builder);
+          if (!builder->resolver_registry()->HasResolverFactory("binder")) {
+            // Binder resolver will only be registered on platforms that support
+            // binder transport. If it is not registered on current platform, we
+            // manually register it here for testing purpose.
+            RegisterBinderResolver(builder);
+            ASSERT_TRUE(
+                builder->resolver_registry()->HasResolverFactory("binder"));
+          }
+        });
     grpc_init();
-    if (grpc_core::ResolverRegistry::LookupResolverFactory("binder") ==
-        nullptr) {
-      // Binder resolver will only be registered on platforms that support
-      // binder transport. If it is not registered on current platform, we
-      // manually register it here for testing purpose.
-      grpc_resolver_binder_init();
-      ASSERT_TRUE(grpc_core::ResolverRegistry::LookupResolverFactory("binder"));
+    if (grpc_core::CoreConfiguration::Get()
+            .resolver_registry()
+            .LookupResolverFactory("binder") == nullptr) {
     }
   }
   static void TearDownTestSuite() { grpc_shutdown(); }
@@ -88,7 +102,7 @@
 
   void TestSucceeds(const char* string, const std::string& expected_path) {
     gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
-            factory_->scheme());
+            std::string(factory_->scheme()).c_str());
     grpc_core::ExecCtx exec_ctx;
     absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
     ASSERT_TRUE(uri.ok()) << uri.status().ToString();
@@ -104,7 +118,7 @@
 
   void TestFails(const char* string) {
     gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
-            factory_->scheme());
+            std::string(factory_->scheme()).c_str());
     grpc_core::ExecCtx exec_ctx;
     absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
     ASSERT_TRUE(uri.ok()) << uri.status().ToString();
diff --git a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
index b8ae31f..b440454 100644
--- a/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_connectivity_test.cc
@@ -23,6 +23,7 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/resolve_address_impl.h"
 #include "src/core/lib/iomgr/timer.h"
@@ -121,8 +122,9 @@
 static grpc_core::OrphanablePtr<grpc_core::Resolver> create_resolver(
     const char* name,
     std::unique_ptr<grpc_core::Resolver::ResultHandler> result_handler) {
-  grpc_core::ResolverFactory* factory =
-      grpc_core::ResolverRegistry::LookupResolverFactory("dns");
+  grpc_core::ResolverFactory* factory = grpc_core::CoreConfiguration::Get()
+                                            .resolver_registry()
+                                            .LookupResolverFactory("dns");
   absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(name);
   if (!uri.ok()) {
     gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
diff --git a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
index 6a89237..a610ca9 100644
--- a/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_cooldown_test.cc
@@ -25,6 +25,7 @@
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/work_serializer.h"
@@ -286,12 +287,13 @@
   OnResolutionCallbackArg* res_cb_arg =
       static_cast<OnResolutionCallbackArg*>(arg);
   res_cb_arg->result_handler = new ResultHandler();
-  grpc_core::ResolverFactory* factory =
-      grpc_core::ResolverRegistry::LookupResolverFactory("dns");
+  grpc_core::ResolverFactory* factory = grpc_core::CoreConfiguration::Get()
+                                            .resolver_registry()
+                                            .LookupResolverFactory("dns");
   absl::StatusOr<grpc_core::URI> uri =
       grpc_core::URI::Parse(res_cb_arg->uri_str);
   gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", res_cb_arg->uri_str,
-          factory->scheme());
+          std::string(factory->scheme()).c_str());
   if (!uri.ok()) {
     gpr_log(GPR_ERROR, "%s", uri.status().ToString().c_str());
     GPR_ASSERT(uri.ok());
diff --git a/test/core/client_channel/resolvers/dns_resolver_test.cc b/test/core/client_channel/resolvers/dns_resolver_test.cc
index 4752463..bd69f37 100644
--- a/test/core/client_channel/resolvers/dns_resolver_test.cc
+++ b/test/core/client_channel/resolvers/dns_resolver_test.cc
@@ -23,6 +23,7 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h"
 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/memory.h"
 #include "src/core/lib/iomgr/work_serializer.h"
@@ -38,7 +39,7 @@
 static void test_succeeds(grpc_core::ResolverFactory* factory,
                           const char* string) {
   gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
-          factory->scheme());
+          std::string(factory->scheme()).c_str());
   grpc_core::ExecCtx exec_ctx;
   absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
   if (!uri.ok()) {
@@ -57,7 +58,7 @@
 static void test_fails(grpc_core::ResolverFactory* factory,
                        const char* string) {
   gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
-          factory->scheme());
+          std::string(factory->scheme()).c_str());
   grpc_core::ExecCtx exec_ctx;
   absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
   if (!uri.ok()) {
@@ -80,8 +81,9 @@
   auto work_serializer = std::make_shared<grpc_core::WorkSerializer>();
   g_work_serializer = &work_serializer;
 
-  grpc_core::ResolverFactory* dns =
-      grpc_core::ResolverRegistry::LookupResolverFactory("dns");
+  grpc_core::ResolverFactory* dns = grpc_core::CoreConfiguration::Get()
+                                        .resolver_registry()
+                                        .LookupResolverFactory("dns");
 
   test_succeeds(dns, "dns:10.2.1.1");
   test_succeeds(dns, "dns:10.2.1.1:1234");
diff --git a/test/core/client_channel/resolvers/fake_resolver_test.cc b/test/core/client_channel/resolvers/fake_resolver_test.cc
index 8f3c837..030c96e 100644
--- a/test/core/client_channel/resolvers/fake_resolver_test.cc
+++ b/test/core/client_channel/resolvers/fake_resolver_test.cc
@@ -29,6 +29,7 @@
 
 #include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
 #include "src/core/lib/iomgr/work_serializer.h"
 #include "src/core/lib/resolver/resolver_registry.h"
@@ -68,8 +69,9 @@
     std::shared_ptr<grpc_core::WorkSerializer> work_serializer,
     grpc_core::FakeResolverResponseGenerator* response_generator,
     std::unique_ptr<grpc_core::Resolver::ResultHandler> result_handler) {
-  grpc_core::ResolverFactory* factory =
-      grpc_core::ResolverRegistry::LookupResolverFactory("fake");
+  grpc_core::ResolverFactory* factory = grpc_core::CoreConfiguration::Get()
+                                            .resolver_registry()
+                                            .LookupResolverFactory("fake");
   grpc_arg generator_arg =
       grpc_core::FakeResolverResponseGenerator::MakeChannelArg(
           response_generator);
diff --git a/test/core/client_channel/resolvers/sockaddr_resolver_test.cc b/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
index 07d8af2..ea2d099 100644
--- a/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
+++ b/test/core/client_channel/resolvers/sockaddr_resolver_test.cc
@@ -24,6 +24,7 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/iomgr/work_serializer.h"
 #include "src/core/lib/resolver/resolver_registry.h"
 #include "test/core/util/test_config.h"
@@ -38,7 +39,7 @@
 static void test_succeeds(grpc_core::ResolverFactory* factory,
                           const char* string) {
   gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
-          factory->scheme());
+          std::string(factory->scheme()).c_str());
   grpc_core::ExecCtx exec_ctx;
   absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
   if (!uri.ok()) {
@@ -61,7 +62,7 @@
 static void test_fails(grpc_core::ResolverFactory* factory,
                        const char* string) {
   gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
-          factory->scheme());
+          std::string(factory->scheme()).c_str());
   grpc_core::ExecCtx exec_ctx;
   absl::StatusOr<grpc_core::URI> uri = grpc_core::URI::Parse(string);
   if (!uri.ok()) {
@@ -84,10 +85,12 @@
   auto work_serializer = std::make_shared<grpc_core::WorkSerializer>();
   g_work_serializer = &work_serializer;
 
-  grpc_core::ResolverFactory* ipv4 =
-      grpc_core::ResolverRegistry::LookupResolverFactory("ipv4");
-  grpc_core::ResolverFactory* ipv6 =
-      grpc_core::ResolverRegistry::LookupResolverFactory("ipv6");
+  grpc_core::ResolverFactory* ipv4 = grpc_core::CoreConfiguration::Get()
+                                         .resolver_registry()
+                                         .LookupResolverFactory("ipv4");
+  grpc_core::ResolverFactory* ipv6 = grpc_core::CoreConfiguration::Get()
+                                         .resolver_registry()
+                                         .LookupResolverFactory("ipv6");
 
   test_fails(ipv4, "ipv4:10.2.1.1");
   test_succeeds(ipv4, "ipv4:10.2.1.1:1234");
@@ -104,10 +107,13 @@
   test_fails(ipv6, "ipv6:www.google.com");
 
 #ifdef GRPC_HAVE_UNIX_SOCKET
-  grpc_core::ResolverFactory* uds =
-      grpc_core::ResolverRegistry::LookupResolverFactory("unix");
+  grpc_core::ResolverFactory* uds = grpc_core::CoreConfiguration::Get()
+                                        .resolver_registry()
+                                        .LookupResolverFactory("unix");
   grpc_core::ResolverFactory* uds_abstract =
-      grpc_core::ResolverRegistry::LookupResolverFactory("unix-abstract");
+      grpc_core::CoreConfiguration::Get()
+          .resolver_registry()
+          .LookupResolverFactory("unix-abstract");
 
   test_succeeds(uds, "unix:///tmp/sockaddr_resolver_test");
   test_succeeds(uds_abstract, "unix-abstract:sockaddr_resolver_test");
diff --git a/test/core/config/BUILD b/test/core/config/BUILD
index 0d4ac2c..d40d56f 100644
--- a/test/core/config/BUILD
+++ b/test/core/config/BUILD
@@ -26,6 +26,7 @@
     uses_polling = False,
     deps = [
         "//:config",
+        "//:grpc",
         "//test/core/util:grpc_suppressions",
     ],
 )
diff --git a/test/core/surface/BUILD b/test/core/surface/BUILD
index 9d55805..852709e 100644
--- a/test/core/surface/BUILD
+++ b/test/core/surface/BUILD
@@ -31,17 +31,6 @@
 )
 
 grpc_cc_test(
-    name = "channel_create_test",
-    srcs = ["channel_create_test.cc"],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//:grpc",
-        "//test/core/util:grpc_test_util",
-    ],
-)
-
-grpc_cc_test(
     name = "grpc_completion_queue_test",
     srcs = ["completion_queue_test.cc"],
     language = "C++",
diff --git a/test/core/surface/channel_create_test.cc b/test/core/surface/channel_create_test.cc
deleted file mode 100644
index ae75463..0000000
--- a/test/core/surface/channel_create_test.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015 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 <string.h>
-
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-#include <grpc/support/log.h>
-
-#include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/resolver/resolver_registry.h"
-#include "src/core/lib/surface/channel.h"
-#include "test/core/util/test_config.h"
-
-void test_unknown_scheme_target(void) {
-  grpc_channel* chan;
-  /* avoid default prefix */
-  grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
-  grpc_core::ResolverRegistry::Builder::InitRegistry();
-
-  grpc_channel_credentials* creds = grpc_insecure_credentials_create();
-  chan = grpc_channel_create("blah://blah", creds, nullptr);
-  grpc_channel_credentials_release(creds);
-  GPR_ASSERT(chan != nullptr);
-
-  grpc_core::ExecCtx exec_ctx;
-  grpc_channel_element* elem =
-      grpc_channel_stack_element(grpc_channel_get_channel_stack(chan), 0);
-  GPR_ASSERT(0 == strcmp(elem->filter->name, "lame-client"));
-
-  grpc_channel_destroy(chan);
-}
-
-int main(int argc, char** argv) {
-  grpc::testing::TestEnvironment env(argc, argv);
-  grpc_init();
-  test_unknown_scheme_target();
-  grpc_shutdown();
-  return 0;
-}
diff --git a/test/core/surface/secure_channel_create_test.cc b/test/core/surface/secure_channel_create_test.cc
index 8c7d396..9b2afa4 100644
--- a/test/core/surface/secure_channel_create_test.cc
+++ b/test/core/surface/secure_channel_create_test.cc
@@ -22,6 +22,7 @@
 #include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/resolver/resolver_registry.h"
 #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 #include "src/core/lib/security/security_connector/security_connector.h"
@@ -29,8 +30,6 @@
 #include "test/core/util/test_config.h"
 
 void test_unknown_scheme_target(void) {
-  grpc_core::ResolverRegistry::Builder::ShutdownRegistry();
-  grpc_core::ResolverRegistry::Builder::InitRegistry();
   grpc_channel_credentials* creds =
       grpc_fake_transport_security_credentials_create();
   grpc_channel* chan = grpc_channel_create("blah://blah", creds, nullptr);
@@ -69,7 +68,13 @@
   grpc_init();
   test_security_connector_already_in_arg();
   test_null_creds();
-  test_unknown_scheme_target();
+  grpc_core::CoreConfiguration::RunWithSpecialConfiguration(
+      [](grpc_core::CoreConfiguration::Builder* builder) {
+        BuildCoreConfiguration(builder);
+        // Avoid default prefix
+        builder->resolver_registry()->Reset();
+      },
+      []() { test_unknown_scheme_target(); });
   grpc_shutdown();
   return 0;
 }
diff --git a/test/cpp/naming/cancel_ares_query_test.cc b/test/cpp/naming/cancel_ares_query_test.cc
index ecd3777..3c96e29 100644
--- a/test/cpp/naming/cancel_ares_query_test.cc
+++ b/test/cpp/naming/cancel_ares_query_test.cc
@@ -35,6 +35,7 @@
 
 #include "src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/orphanable.h"
@@ -165,7 +166,7 @@
       fake_dns_server.port());
   // create resolver and resolve
   grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
-      grpc_core::ResolverRegistry::CreateResolver(
+      grpc_core::CoreConfiguration::Get().resolver_registry().CreateResolver(
           client_target.c_str(), nullptr, args->pollset_set, args->lock,
           std::unique_ptr<grpc_core::Resolver::ResultHandler>(
               new AssertFailureResultHandler(args)));
diff --git a/test/cpp/naming/resolver_component_test.cc b/test/cpp/naming/resolver_component_test.cc
index 65d07c5..4991b40 100644
--- a/test/cpp/naming/resolver_component_test.cc
+++ b/test/cpp/naming/resolver_component_test.cc
@@ -46,6 +46,7 @@
 #include "src/core/lib/address_utils/parse_address.h"
 #include "src/core/lib/address_utils/sockaddr_utils.h"
 #include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/config/core_configuration.h"
 #include "src/core/lib/gpr/string.h"
 #include "src/core/lib/gprpp/host_port.h"
 #include "src/core/lib/gprpp/orphanable.h"
@@ -639,7 +640,7 @@
   }
   // create resolver and resolve
   grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
-      grpc_core::ResolverRegistry::CreateResolver(
+      grpc_core::CoreConfiguration::Get().resolver_registry().CreateResolver(
           whole_uri.c_str(), resolver_args, args.pollset_set, args.lock,
           CreateResultHandler(&args));
   grpc_channel_args_destroy(resolver_args);
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index dd1f9ae..4edc3d4 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -2110,6 +2110,7 @@
 src/core/lib/iomgr/resolved_address.h \
 src/core/lib/iomgr/sockaddr.h \
 src/core/lib/iomgr/sockaddr_posix.h \
+src/core/lib/iomgr/sockaddr_utils_posix.cc \
 src/core/lib/iomgr/sockaddr_windows.h \
 src/core/lib/iomgr/socket_factory_posix.cc \
 src/core/lib/iomgr/socket_factory_posix.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index b59ba1a..8e1ce4b 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1905,6 +1905,7 @@
 src/core/lib/iomgr/resolved_address.h \
 src/core/lib/iomgr/sockaddr.h \
 src/core/lib/iomgr/sockaddr_posix.h \
+src/core/lib/iomgr/sockaddr_utils_posix.cc \
 src/core/lib/iomgr/sockaddr_windows.h \
 src/core/lib/iomgr/socket_factory_posix.cc \
 src/core/lib/iomgr/socket_factory_posix.h \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 5260489..2c68d00 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -564,30 +564,6 @@
     "flaky": false,
     "gtest": false,
     "language": "c",
-    "name": "channel_create_test",
-    "platforms": [
-      "linux",
-      "mac",
-      "posix",
-      "windows"
-    ],
-    "uses_polling": true
-  },
-  {
-    "args": [],
-    "benchmark": false,
-    "ci_platforms": [
-      "linux",
-      "mac",
-      "posix",
-      "windows"
-    ],
-    "cpu_cost": 1.0,
-    "exclude_configs": [],
-    "exclude_iomgrs": [],
-    "flaky": false,
-    "gtest": false,
-    "language": "c",
     "name": "channel_stack_test",
     "platforms": [
       "linux",