diff --git a/BUILD b/BUILD
index 5aae602ebed..b90d3e18487 100644
--- a/BUILD
+++ b/BUILD
@@ -1928,6 +1928,7 @@ grpc_cc_library(
"grpc_resolver_fake",
"grpc_resolver_dns_native",
"grpc_resolver_sockaddr",
+ "grpc_resolver_binder",
"grpc_transport_chttp2_client_insecure",
"grpc_transport_chttp2_server_insecure",
"grpc_transport_inproc",
@@ -2968,6 +2969,23 @@ grpc_cc_library(
],
)
+grpc_cc_library(
+ name = "grpc_resolver_binder",
+ srcs = [
+ "src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc",
+ ],
+ external_deps = [
+ "absl/strings",
+ ],
+ language = "c++",
+ deps = [
+ "gpr_base",
+ "grpc_base",
+ "grpc_client_channel",
+ "slice",
+ ],
+)
+
grpc_cc_library(
name = "grpc_resolver_fake",
srcs = ["src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc"],
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 88bb75abd50..6f9f00b9d82 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -751,6 +751,7 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx bdp_estimator_test)
endif()
+ add_dependencies(buildtests_cxx binder_resolver_test)
add_dependencies(buildtests_cxx binder_server_test)
add_dependencies(buildtests_cxx binder_transport_test)
add_dependencies(buildtests_cxx bitset_test)
@@ -1529,6 +1530,7 @@ add_library(grpc
src/core/ext/filters/client_channel/local_subchannel_pool.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
+ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
@@ -2365,6 +2367,7 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/local_subchannel_pool.cc
src/core/ext/filters/client_channel/proxy_mapper_registry.cc
src/core/ext/filters/client_channel/resolver.cc
+ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
@@ -8295,6 +8298,41 @@ endif()
endif()
if(gRPC_BUILD_TESTS)
+add_executable(binder_resolver_test
+ test/core/client_channel/resolvers/binder_resolver_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(binder_resolver_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}
+ third_party/googletest/googletest/include
+ third_party/googletest/googletest
+ third_party/googletest/googlemock/include
+ third_party/googletest/googlemock
+ ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(binder_resolver_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+)
+
+
+endif()
+if(gRPC_BUILD_TESTS)
+
add_executable(binder_server_test
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc
diff --git a/Makefile b/Makefile
index bad402e45c7..fa660d063be 100644
--- a/Makefile
+++ b/Makefile
@@ -1082,6 +1082,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/local_subchannel_pool.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
+ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
@@ -1764,6 +1765,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/local_subchannel_pool.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
+ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 09db7946bf3..4fdbed6ccb8 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -996,6 +996,7 @@ libs:
- src/core/ext/filters/client_channel/local_subchannel_pool.cc
- src/core/ext/filters/client_channel/proxy_mapper_registry.cc
- src/core/ext/filters/client_channel/resolver.cc
+ - src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
@@ -1968,6 +1969,7 @@ libs:
- src/core/ext/filters/client_channel/local_subchannel_pool.cc
- src/core/ext/filters/client_channel/proxy_mapper_registry.cc
- src/core/ext/filters/client_channel/resolver.cc
+ - src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc
- src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
@@ -4609,6 +4611,15 @@ targets:
- posix
- mac
uses_polling: false
+- name: binder_resolver_test
+ gtest: true
+ build: test
+ language: c++
+ headers: []
+ src:
+ - test/core/client_channel/resolvers/binder_resolver_test.cc
+ deps:
+ - grpc_test_util
- name: binder_server_test
gtest: true
build: test
diff --git a/config.m4 b/config.m4
index 721365d8989..9bfff142adc 100644
--- a/config.m4
+++ b/config.m4
@@ -77,6 +77,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/local_subchannel_pool.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/resolver.cc \
+ src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
@@ -1074,6 +1075,7 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/round_robin)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/weighted_target)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/xds)
+ PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/binder)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/c_ares)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/resolver/dns/native)
diff --git a/config.w32 b/config.w32
index 849335d2b73..3b18fa79da0 100644
--- a/config.w32
+++ b/config.w32
@@ -43,6 +43,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\local_subchannel_pool.cc " +
"src\\core\\ext\\filters\\client_channel\\proxy_mapper_registry.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver.cc " +
+ "src\\core\\ext\\filters\\client_channel\\resolver\\binder\\binder_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_event_engine.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " +
@@ -1073,6 +1074,7 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\weighted_target");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\lb_policy\\xds");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver");
+ FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\binder");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\ext\\filters\\client_channel\\resolver\\dns\\native");
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 89cedca67f8..18feb147e7d 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -257,6 +257,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/proxy_mapper_registry.h',
'src/core/ext/filters/client_channel/resolver.cc',
'src/core/ext/filters/client_channel/resolver.h',
+ 'src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc',
diff --git a/grpc.gemspec b/grpc.gemspec
index e2d63d1c2fc..de7cbc64d07 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -177,6 +177,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/proxy_mapper_registry.h )
s.files += %w( src/core/ext/filters/client_channel/resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver.h )
+ s.files += %w( src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc )
diff --git a/grpc.gyp b/grpc.gyp
index 81b7f97f316..fd67abbdfb5 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -523,6 +523,7 @@
'src/core/ext/filters/client_channel/local_subchannel_pool.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
+ 'src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
@@ -1180,6 +1181,7 @@
'src/core/ext/filters/client_channel/local_subchannel_pool.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
+ 'src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
diff --git a/package.xml b/package.xml
index f26e9ed734e..8dd1784584f 100644
--- a/package.xml
+++ b/package.xml
@@ -157,6 +157,7 @@
+
diff --git a/src/core/ext/filters/client_channel/resolver/binder/README.md b/src/core/ext/filters/client_channel/resolver/binder/README.md
new file mode 100644
index 00000000000..b60296765d5
--- /dev/null
+++ b/src/core/ext/filters/client_channel/resolver/binder/README.md
@@ -0,0 +1,9 @@
+Support for resolving the scheme used by binder transport implementation.
+
+The URI's authority is required to be empty.
+
+The path is used as the identifiers of endpoint binder objects and the length
+limit of the identifier is the same as unix socket length limit.
+
+The length limit of the path should at least be 100 characters long. This is
+guaranteed by `static_assert` in the implementation.
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
new file mode 100644
index 00000000000..68f21c80e1a
--- /dev/null
+++ b/src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc
@@ -0,0 +1,139 @@
+// Copyright 2021 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
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_HAVE_UNIX_SOCKET
+
+#include
+
+#include
+#include
+
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/ext/filters/client_channel/server_address.h"
+#include "src/core/lib/address_utils/parse_address.h"
+#include "src/core/lib/channel/channel_args.h"
+#include "src/core/lib/gpr/string.h"
+
+namespace grpc_core {
+namespace {
+
+class BinderResolver : public Resolver {
+ public:
+ BinderResolver(ServerAddressList addresses, ResolverArgs args)
+ : result_handler_(std::move(args.result_handler)),
+ addresses_(std::move(addresses)),
+ channel_args_(grpc_channel_args_copy(args.args)) {}
+
+ ~BinderResolver() override { grpc_channel_args_destroy(channel_args_); };
+
+ void StartLocked() override {
+ Result result;
+ result.addresses = std::move(addresses_);
+ result.args = channel_args_;
+ channel_args_ = nullptr;
+ result_handler_->ReturnResult(std::move(result));
+ }
+
+ void ShutdownLocked() override {}
+
+ private:
+ std::unique_ptr result_handler_;
+ ServerAddressList addresses_;
+ const grpc_channel_args* channel_args_ = nullptr;
+};
+
+class BinderResolverFactory : public ResolverFactory {
+ public:
+ bool IsValidUri(const URI& uri) const override {
+ return ParseUri(uri, nullptr);
+ }
+
+ OrphanablePtr CreateResolver(ResolverArgs args) const override {
+ ServerAddressList addresses;
+ if (!ParseUri(args.uri, &addresses)) return nullptr;
+ return MakeOrphanable(std::move(addresses),
+ 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) {
+ path = absl::StripPrefix(path, "/");
+ if (path.empty()) {
+ return GRPC_ERROR_CREATE_FROM_CPP_STRING("path is empty");
+ }
+ // Store parsed path in a unix socket so it can be reinterpreted as
+ // sockaddr. An invalid address family (AF_MAX) is set to make sure it won't
+ // be accidentally used.
+ memset(resolved_addr, 0, sizeof(*resolved_addr));
+ struct sockaddr_un* un =
+ reinterpret_cast(resolved_addr->addr);
+ un->sun_family = AF_MAX;
+ static_assert(sizeof(un->sun_path) >= 101,
+ "unix socket path size is unexpectedly short");
+ if (path.size() + 1 > sizeof(un->sun_path)) {
+ return GRPC_ERROR_CREATE_FROM_CPP_STRING(
+ absl::StrCat(path, " is too long to be handled"));
+ }
+ // `un` has already be set to zero, no need to append null after the string
+ memcpy(un->sun_path, path.data(), path.size());
+ resolved_addr->len =
+ static_cast(sizeof(un->sun_family) + path.size() + 1);
+ return GRPC_ERROR_NONE;
+ }
+
+ static bool ParseUri(const URI& uri, ServerAddressList* addresses) {
+ grpc_resolved_address addr;
+ {
+ if (!uri.authority().empty()) {
+ gpr_log(GPR_ERROR, "authority is not supported in binder scheme");
+ return false;
+ }
+ grpc_error_handle error = BinderAddrPopulate(uri.path(), &addr);
+ if (error != GRPC_ERROR_NONE) {
+ gpr_log(GPR_ERROR, "%s", grpc_error_std_string(error).c_str());
+ GRPC_ERROR_UNREF(error);
+ return false;
+ }
+ }
+ if (addresses != nullptr) {
+ addresses->emplace_back(addr, nullptr /* args */);
+ }
+ return true;
+ }
+};
+
+} // namespace
+} // namespace grpc_core
+
+void grpc_resolver_binder_init() {
+ grpc_core::ResolverRegistry::Builder::RegisterResolverFactory(
+ absl::make_unique());
+}
+
+void grpc_resolver_binder_shutdown() {}
+
+#else
+
+void grpc_resolver_binder_init() {}
+
+void grpc_resolver_binder_shutdown() {}
+
+#endif
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index 134b9d34f05..39bfaed4f84 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -87,6 +87,11 @@ void GoogleCloud2ProdResolverShutdown();
} // namespace grpc_core
#endif
+#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_chttp2_plugin_init, grpc_chttp2_plugin_shutdown);
grpc_register_plugin(grpc_core::ServiceConfigParserInit,
@@ -136,6 +141,11 @@ void grpc_register_built_in_plugins(void) {
grpc_register_plugin(grpc_core::GoogleCloud2ProdResolverInit,
grpc_core::GoogleCloud2ProdResolverShutdown);
#endif
+
+#ifdef GPR_SUPPORT_BINDER_TRANSPORT
+ grpc_register_plugin(grpc_resolver_binder_init,
+ grpc_resolver_binder_shutdown);
+#endif
}
namespace grpc_core {
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index fe2f0b4498a..a7d256dc16b 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -52,6 +52,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/local_subchannel_pool.cc',
'src/core/ext/filters/client_channel/proxy_mapper_registry.cc',
'src/core/ext/filters/client_channel/resolver.cc',
+ 'src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc',
'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
diff --git a/test/core/client_channel/resolvers/BUILD b/test/core/client_channel/resolvers/BUILD
index b50f4373eba..224df41d229 100644
--- a/test/core/client_channel/resolvers/BUILD
+++ b/test/core/client_channel/resolvers/BUILD
@@ -18,6 +18,20 @@ grpc_package(name = "test/core/client_channel/resolvers")
licenses(["notice"])
+grpc_cc_test(
+ name = "binder_resolver_test",
+ srcs = ["binder_resolver_test.cc"],
+ external_deps = [
+ "gtest",
+ ],
+ language = "C++",
+ deps = [
+ "//:gpr",
+ "//:grpc",
+ "//test/core/util:grpc_test_util",
+ ],
+)
+
grpc_cc_test(
name = "dns_resolver_connectivity_using_ares_test",
srcs = ["dns_resolver_connectivity_test.cc"],
diff --git a/test/core/client_channel/resolvers/binder_resolver_test.cc b/test/core/client_channel/resolvers/binder_resolver_test.cc
new file mode 100644
index 00000000000..4065a393891
--- /dev/null
+++ b/test/core/client_channel/resolvers/binder_resolver_test.cc
@@ -0,0 +1,181 @@
+// Copyright 2021 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
+
+#include "src/core/lib/iomgr/port.h"
+#include "test/core/util/test_config.h"
+
+#ifdef GRPC_HAVE_UNIX_SOCKET
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+#include "src/core/ext/filters/client_channel/resolver_registry.h"
+#include "src/core/lib/channel/channel_args.h"
+
+// Registers the factory with `grpc_core::ResolverRegistry`. Defined in
+// binder_resolver.cc
+void grpc_resolver_binder_init(void);
+
+namespace {
+
+class BinderResolverTest : public ::testing::Test {
+ public:
+ BinderResolverTest() {
+ factory_ = grpc_core::ResolverRegistry::LookupResolverFactory("binder");
+ }
+ ~BinderResolverTest() override {}
+ static void SetUpTestSuite() {
+ 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"));
+ }
+ }
+ static void TearDownTestSuite() { grpc_shutdown(); }
+
+ void SetUp() override { ASSERT_TRUE(factory_); }
+
+ class ResultHandler : public grpc_core::Resolver::ResultHandler {
+ public:
+ ResultHandler() = default;
+
+ explicit ResultHandler(const std::string& expected_binder_id)
+ : expect_result_(true), expected_binder_id_(expected_binder_id) {}
+
+ void ReturnResult(grpc_core::Resolver::Result result) override {
+ EXPECT_TRUE(expect_result_);
+ ASSERT_TRUE(result.addresses.size() == 1);
+ grpc_core::ServerAddress addr = result.addresses[0];
+ const struct sockaddr_un* un =
+ reinterpret_cast(addr.address().addr);
+ EXPECT_EQ(addr.address().len,
+ sizeof(un->sun_family) + expected_binder_id_.length() + 1);
+ EXPECT_EQ(un->sun_family, AF_MAX);
+ EXPECT_EQ(un->sun_path, expected_binder_id_);
+ }
+
+ void ReturnError(grpc_error_handle error) override {
+ GRPC_ERROR_UNREF(error);
+ }
+
+ private:
+ // Whether we expect ReturnResult function to be invoked
+ bool expect_result_ = false;
+
+ std::string expected_binder_id_;
+ };
+
+ void TestSucceeds(const char* string, const std::string& expected_path) {
+ gpr_log(GPR_DEBUG, "test: '%s' should be valid for '%s'", string,
+ factory_->scheme());
+ grpc_core::ExecCtx exec_ctx;
+ absl::StatusOr uri = grpc_core::URI::Parse(string);
+ ASSERT_TRUE(uri.ok()) << uri.status().ToString();
+ grpc_core::ResolverArgs args;
+ args.uri = std::move(*uri);
+ args.result_handler =
+ absl::make_unique(expected_path);
+ grpc_core::OrphanablePtr resolver =
+ factory_->CreateResolver(std::move(args));
+ ASSERT_TRUE(resolver != nullptr);
+ resolver->StartLocked();
+ }
+
+ void TestFails(const char* string) {
+ gpr_log(GPR_DEBUG, "test: '%s' should be invalid for '%s'", string,
+ factory_->scheme());
+ grpc_core::ExecCtx exec_ctx;
+ absl::StatusOr uri = grpc_core::URI::Parse(string);
+ ASSERT_TRUE(uri.ok()) << uri.status().ToString();
+ grpc_core::ResolverArgs args;
+ args.uri = std::move(*uri);
+ args.result_handler =
+ absl::make_unique();
+ grpc_core::OrphanablePtr resolver =
+ factory_->CreateResolver(std::move(args));
+ EXPECT_TRUE(resolver == nullptr);
+ }
+
+ private:
+ grpc_core::ResolverFactory* factory_;
+};
+
+} // namespace
+
+// Authority is not allowed
+TEST_F(BinderResolverTest, AuthorityPresents) {
+ TestFails("binder://example");
+ TestFails("binder://google.com");
+ TestFails("binder://google.com/test");
+}
+
+// Path cannot be empty
+TEST_F(BinderResolverTest, EmptyPath) {
+ TestFails("binder:");
+ TestFails("binder:/");
+ TestFails("binder://");
+}
+
+TEST_F(BinderResolverTest, PathLength) {
+ // Note that we have a static assert in binder_resolver.cc that checks
+ // sizeof(sockaddr_un::sun_path) is greater than 100
+
+ // 100 character path should be fine
+ TestSucceeds(("binder:l" + std::string(98, 'o') + "g").c_str(),
+ "l" + std::string(98, 'o') + "g");
+
+ // 200 character path most likely will fail
+ TestFails(("binder:l" + std::string(198, 'o') + "g").c_str());
+}
+
+TEST_F(BinderResolverTest, SlashPrefixes) {
+ TestSucceeds("binder:///test", "test");
+ TestSucceeds("binder:////test", "/test");
+}
+
+TEST_F(BinderResolverTest, ValidCases) {
+ TestSucceeds("binder:[[", "[[");
+ TestSucceeds("binder:google!com", "google!com");
+ TestSucceeds("binder:test/", "test/");
+ TestSucceeds("binder:test:", "test:");
+
+ TestSucceeds("binder:e", "e");
+ TestSucceeds("binder:example", "example");
+ TestSucceeds("binder:google.com", "google.com");
+ TestSucceeds("binder:~", "~");
+ TestSucceeds("binder:12345", "12345");
+ TestSucceeds(
+ "binder:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._"
+ "~",
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~");
+}
+
+#endif
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ grpc::testing::TestEnvironment env(argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 694155faed0..b1f6ff44fa8 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1114,6 +1114,7 @@ src/core/ext/filters/client_channel/proxy_mapper_registry.cc \
src/core/ext/filters/client_channel/proxy_mapper_registry.h \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver.h \
+src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 79da53a775c..d09a5e498ee 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -939,6 +939,8 @@ src/core/ext/filters/client_channel/proxy_mapper_registry.h \
src/core/ext/filters/client_channel/resolver.cc \
src/core/ext/filters/client_channel/resolver.h \
src/core/ext/filters/client_channel/resolver/README.md \
+src/core/ext/filters/client_channel/resolver/binder/README.md \
+src/core/ext/filters/client_channel/resolver/binder/binder_resolver.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h \
src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_event_engine.cc \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 0df688f96cd..6bbed15c436 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -3379,6 +3379,30 @@
],
"uses_polling": false
},
+ {
+ "args": [],
+ "benchmark": false,
+ "ci_platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "cpu_cost": 1.0,
+ "exclude_configs": [],
+ "exclude_iomgrs": [],
+ "flaky": false,
+ "gtest": true,
+ "language": "c++",
+ "name": "binder_resolver_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": true
+ },
{
"args": [],
"benchmark": false,