From 3df113f6d654f7f9c0ca756782ba7276c892da9c Mon Sep 17 00:00:00 2001 From: Ta-Wei Tu Date: Mon, 6 Sep 2021 14:45:45 +0800 Subject: [PATCH] Add binder server (#27036) Add `grpc::BinderServerCredentials()` and other related functionalities for the server to listen to binder transactions through a phony "binder port". The APIs are temporarily placed in internal headers until the corresponding gRFC is merged. --- CMakeLists.txt | 66 ++++++ build_autogenerated.yaml | 44 ++++ src/core/ext/transport/binder/server/BUILD | 50 +++++ .../transport/binder/server/binder_server.cc | 179 +++++++++++++++ .../transport/binder/server/binder_server.h | 70 ++++++ .../server/binder_server_credentials.cc | 61 +++++ .../binder/server/binder_server_credentials.h | 35 +++ test/core/transport/binder/end2end/BUILD | 17 ++ .../binder/end2end/binder_server_test.cc | 211 ++++++++++++++++++ .../transport/binder/end2end/fake_binder.h | 4 +- tools/run_tests/generated/tests.json | 24 ++ 11 files changed, 758 insertions(+), 3 deletions(-) create mode 100644 src/core/ext/transport/binder/server/BUILD create mode 100644 src/core/ext/transport/binder/server/binder_server.cc create mode 100644 src/core/ext/transport/binder/server/binder_server.h create mode 100644 src/core/ext/transport/binder/server/binder_server_credentials.cc create mode 100644 src/core/ext/transport/binder/server/binder_server_credentials.h create mode 100644 test/core/transport/binder/end2end/binder_server_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 19ec6964ad4..002754c1dda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -753,6 +753,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_server_test) add_dependencies(buildtests_cxx binder_transport_test) add_dependencies(buildtests_cxx bitset_test) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX) @@ -8381,6 +8382,71 @@ endif() 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 + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/simple_messages.grpc.pb.h + ${_gRPC_PROTO_GENS_DIR}/test/core/transport/binder/end2end/echo.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/transport/binder/end2end/echo.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/test/core/transport/binder/end2end/echo.pb.h + ${_gRPC_PROTO_GENS_DIR}/test/core/transport/binder/end2end/echo.grpc.pb.h + src/core/ext/transport/binder/client/channel_create_impl.cc + src/core/ext/transport/binder/server/binder_server.cc + src/core/ext/transport/binder/server/binder_server_credentials.cc + src/core/ext/transport/binder/transport/binder_transport.cc + src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc + src/core/ext/transport/binder/wire_format/binder_android.cc + src/core/ext/transport/binder/wire_format/binder_constants.cc + src/core/ext/transport/binder/wire_format/transaction.cc + src/core/ext/transport/binder/wire_format/wire_reader_impl.cc + src/core/ext/transport/binder/wire_format/wire_writer.cc + test/core/transport/binder/end2end/binder_server_test.cc + test/core/transport/binder/end2end/echo_service.cc + test/core/transport/binder/end2end/fake_binder.cc + test/cpp/end2end/test_service_impl.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + +target_include_directories(binder_server_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_server_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + absl::random_random + grpc++_test_util +) + + +endif() +if(gRPC_BUILD_TESTS) + add_executable(binder_transport_test src/core/ext/transport/binder/transport/binder_transport.cc src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index fabcebbbad0..ad74c610388 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -4553,6 +4553,50 @@ targets: - posix - mac uses_polling: false +- name: binder_server_test + gtest: true + build: test + language: c++ + headers: + - src/core/ext/transport/binder/client/channel_create_impl.h + - src/core/ext/transport/binder/server/binder_server.h + - src/core/ext/transport/binder/server/binder_server_credentials.h + - src/core/ext/transport/binder/transport/binder_stream.h + - src/core/ext/transport/binder/transport/binder_transport.h + - src/core/ext/transport/binder/utils/transport_stream_receiver.h + - src/core/ext/transport/binder/utils/transport_stream_receiver_impl.h + - src/core/ext/transport/binder/wire_format/binder.h + - src/core/ext/transport/binder/wire_format/binder_android.h + - src/core/ext/transport/binder/wire_format/binder_constants.h + - src/core/ext/transport/binder/wire_format/transaction.h + - src/core/ext/transport/binder/wire_format/wire_reader.h + - src/core/ext/transport/binder/wire_format/wire_reader_impl.h + - src/core/ext/transport/binder/wire_format/wire_writer.h + - test/core/transport/binder/end2end/echo_service.h + - test/core/transport/binder/end2end/fake_binder.h + - test/cpp/end2end/test_service_impl.h + src: + - src/proto/grpc/testing/echo.proto + - src/proto/grpc/testing/echo_messages.proto + - src/proto/grpc/testing/simple_messages.proto + - test/core/transport/binder/end2end/echo.proto + - src/core/ext/transport/binder/client/channel_create_impl.cc + - src/core/ext/transport/binder/server/binder_server.cc + - src/core/ext/transport/binder/server/binder_server_credentials.cc + - src/core/ext/transport/binder/transport/binder_transport.cc + - src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc + - src/core/ext/transport/binder/wire_format/binder_android.cc + - src/core/ext/transport/binder/wire_format/binder_constants.cc + - src/core/ext/transport/binder/wire_format/transaction.cc + - src/core/ext/transport/binder/wire_format/wire_reader_impl.cc + - src/core/ext/transport/binder/wire_format/wire_writer.cc + - test/core/transport/binder/end2end/binder_server_test.cc + - test/core/transport/binder/end2end/echo_service.cc + - test/core/transport/binder/end2end/fake_binder.cc + - test/cpp/end2end/test_service_impl.cc + deps: + - absl/random:random + - grpc++_test_util - name: binder_transport_test gtest: true build: test diff --git a/src/core/ext/transport/binder/server/BUILD b/src/core/ext/transport/binder/server/BUILD new file mode 100644 index 00000000000..a5cf6df3c78 --- /dev/null +++ b/src/core/ext/transport/binder/server/BUILD @@ -0,0 +1,50 @@ +# 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. + +load("//bazel:grpc_build_system.bzl", "grpc_cc_library") + +licenses(["notice"]) + +package( + default_visibility = ["//visibility:public"], + features = [ + "layering_check", + ], +) + +grpc_cc_library( + name = "grpc_transport_binder_server", + srcs = [ + "binder_server.cc", + "binder_server_credentials.cc", + ], + hdrs = [ + "binder_server.h", + "binder_server_credentials.h", + ], + external_deps = [ + "absl/container:flat_hash_map", + "absl/memory", + "absl/status", + ], + language = "c++", + deps = [ + "//:gpr_platform", + "//:grpc++_internals", + "//:grpc_base_c", + "//src/core/ext/transport/binder/transport:binder_transport", + "//src/core/ext/transport/binder/wire_format:binder", + "//src/core/ext/transport/binder/wire_format:binder_android", + ], +) diff --git a/src/core/ext/transport/binder/server/binder_server.cc b/src/core/ext/transport/binder/server/binder_server.cc new file mode 100644 index 00000000000..ffd33dff852 --- /dev/null +++ b/src/core/ext/transport/binder/server/binder_server.cc @@ -0,0 +1,179 @@ +// 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 +#include +#include +#include + +#include "absl/memory/memory.h" +#include "src/core/ext/transport/binder/server/binder_server.h" +#include "src/core/ext/transport/binder/transport/binder_transport.h" +#include "src/core/ext/transport/binder/wire_format/binder_android.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/error_utils.h" + +namespace grpc { +namespace experimental { +namespace binder { + +void* GetEndpointBinder(const std::string& service) { + return grpc_get_endpoint_binder(service); +} + +void AddEndpointBinder(const std::string& service, void* endpoint_binder) { + grpc_add_endpoint_binder(service, endpoint_binder); +} + +void RemoveEndpointBinder(const std::string& service) { + grpc_remove_endpoint_binder(service); +} + +} // namespace binder +} // namespace experimental +} // namespace grpc + +grpc_core::Mutex* g_endpoint_binder_pool_mu = nullptr; +absl::flat_hash_map* g_endpoint_binder_pool = nullptr; + +void grpc_endpoint_binder_pool_init() { + g_endpoint_binder_pool_mu = new grpc_core::Mutex(); + g_endpoint_binder_pool = new absl::flat_hash_map(); +} + +void grpc_endpoint_binder_pool_shutdown() { + g_endpoint_binder_pool_mu->Lock(); + delete g_endpoint_binder_pool; + g_endpoint_binder_pool_mu->Unlock(); + delete g_endpoint_binder_pool_mu; +} + +void grpc_add_endpoint_binder(const std::string& service, + void* endpoint_binder) { + grpc_core::MutexLock lock(g_endpoint_binder_pool_mu); + (*g_endpoint_binder_pool)[service] = endpoint_binder; +} + +void grpc_remove_endpoint_binder(const std::string& service) { + grpc_core::MutexLock lock(g_endpoint_binder_pool_mu); + g_endpoint_binder_pool->erase(service); +} + +void* grpc_get_endpoint_binder(const std::string& service) { + grpc_core::MutexLock lock(g_endpoint_binder_pool_mu); + auto iter = g_endpoint_binder_pool->find(service); + return iter == g_endpoint_binder_pool->end() ? nullptr : iter->second; +} + +namespace grpc_core { + +class BinderServerListener : public Server::ListenerInterface { + public: + BinderServerListener(Server* server, std::string addr, + BinderTxReceiverFactory factory) + : server_(server), addr_(std::move(addr)), factory_(std::move(factory)) {} + + void Start(Server* /*server*/, + const std::vector* /*pollsets*/) override { + tx_receiver_ = factory_([this](transaction_code_t code, + const grpc_binder::ReadableParcel* parcel) { + return OnSetupTransport(code, parcel); + }); + endpoint_binder_ = tx_receiver_->GetRawBinder(); + grpc_add_endpoint_binder(addr_, endpoint_binder_); + } + + channelz::ListenSocketNode* channelz_listen_socket_node() const override { + return nullptr; + } + + void SetOnDestroyDone(grpc_closure* on_destroy_done) override { + on_destroy_done_ = on_destroy_done; + } + + void Orphan() override { delete this; } + + ~BinderServerListener() override { + ExecCtx::Get()->Flush(); + if (on_destroy_done_) { + ExecCtx::Run(DEBUG_LOCATION, on_destroy_done_, GRPC_ERROR_NONE); + ExecCtx::Get()->Flush(); + } + grpc_remove_endpoint_binder(addr_); + } + + private: + absl::Status OnSetupTransport(transaction_code_t code, + const grpc_binder::ReadableParcel* parcel) { + grpc_core::ExecCtx exec_ctx; + if (grpc_binder::BinderTransportTxCode(code) != + grpc_binder::BinderTransportTxCode::SETUP_TRANSPORT) { + return absl::InvalidArgumentError("Not a SETUP_TRANSPORT request"); + } + int version; + absl::Status status = parcel->ReadInt32(&version); + if (!status.ok()) { + return status; + } + gpr_log(GPR_INFO, "version = %d", version); + // TODO(waynetu): Check supported version. + std::unique_ptr client_binder{}; + status = parcel->ReadBinder(&client_binder); + if (!status.ok()) { + return status; + } + if (!client_binder) { + return absl::InvalidArgumentError("NULL binder read from the parcel"); + } + client_binder->Initialize(); + // Finish the second half of SETUP_TRANSPORT in + // grpc_create_binder_transport_server(). + grpc_transport* server_transport = + grpc_create_binder_transport_server(std::move(client_binder)); + GPR_ASSERT(server_transport); + grpc_channel_args* args = grpc_channel_args_copy(server_->channel_args()); + grpc_error_handle error = server_->SetupTransport(server_transport, nullptr, + args, nullptr, nullptr); + grpc_channel_args_destroy(args); + return grpc_error_to_absl_status(error); + } + + Server* server_; + grpc_closure* on_destroy_done_ = nullptr; + std::string addr_; + BinderTxReceiverFactory factory_; + void* endpoint_binder_ = nullptr; + std::unique_ptr tx_receiver_; +}; + +bool AddBinderPort(const std::string& addr, grpc_server* server, + BinderTxReceiverFactory factory) { + const std::string kBinderUriScheme = "binder:"; + if (addr.compare(0, kBinderUriScheme.size(), kBinderUriScheme) != 0) { + return false; + } + size_t pos = kBinderUriScheme.size(); + while (pos < addr.size() && addr[pos] == '/') pos++; + grpc_core::Server* core_server = server->core_server.get(); + core_server->AddListener( + grpc_core::OrphanablePtr( + new grpc_core::BinderServerListener(core_server, addr.substr(pos), + std::move(factory)))); + return true; +} + +} // namespace grpc_core diff --git a/src/core/ext/transport/binder/server/binder_server.h b/src/core/ext/transport/binder/server/binder_server.h new file mode 100644 index 00000000000..9ec1a06afad --- /dev/null +++ b/src/core/ext/transport/binder/server/binder_server.h @@ -0,0 +1,70 @@ +// 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. + +#ifndef GRPC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_H +#define GRPC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_H + +#include + +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "src/core/ext/transport/binder/transport/binder_transport.h" +#include "src/core/ext/transport/binder/wire_format/binder.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/surface/server.h" +#include "src/core/lib/transport/error_utils.h" + +// TODO(waynetu): This is part of the public API and should be moved to the +// include/ folder. +namespace grpc { +namespace experimental { +namespace binder { + +void* GetEndpointBinder(const std::string& service); +void AddEndpointBinder(const std::string& service, void* endpoint_binder); +void RemoveEndpointBinder(const std::string& service); + +} // namespace binder +} // namespace experimental +} // namespace grpc + +extern grpc_core::Mutex* g_endpoint_binder_pool_mu; +extern absl::flat_hash_map* g_endpoint_binder_pool; + +// TODO(waynetu): Can these two functions be called in grpc_init() and +// grpc_shutdown()? +void grpc_endpoint_binder_pool_init(); +void grpc_endpoint_binder_pool_shutdown(); + +void grpc_add_endpoint_binder(const std::string& service, + void* endpoint_binder); +void grpc_remove_endpoint_binder(const std::string& service); +void* grpc_get_endpoint_binder(const std::string& service); + +namespace grpc_core { + +// Consume a callback, produce a transaction listener. This is used to perform +// testing in non-Android environments where the actual binder is not available. +using BinderTxReceiverFactory = + std::function( + grpc_binder::TransactionReceiver::OnTransactCb)>; + +bool AddBinderPort(const std::string& addr, grpc_server* server, + BinderTxReceiverFactory factory); + +} // namespace grpc_core + +#endif // GRPC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_H diff --git a/src/core/ext/transport/binder/server/binder_server_credentials.cc b/src/core/ext/transport/binder/server/binder_server_credentials.cc new file mode 100644 index 00000000000..ee57e6bb901 --- /dev/null +++ b/src/core/ext/transport/binder/server/binder_server_credentials.cc @@ -0,0 +1,61 @@ +// 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 + +#include "src/core/ext/transport/binder/server/binder_server.h" +#include "src/core/ext/transport/binder/wire_format/binder_android.h" + +namespace grpc { +namespace experimental { + +namespace { + +class BinderServerCredentialsImpl final : public ServerCredentials { + public: +#ifdef GPR_ANDROID + int AddPortToServer(const std::string& addr, grpc_server* server) override { + return grpc_core::AddBinderPort( + std::string(addr), server, + [](grpc_binder::TransactionReceiver::OnTransactCb transact_cb) { + return absl::make_unique( + nullptr, std::move(transact_cb)); + }); + } +#else + int AddPortToServer(const std::string& /*addr*/, + grpc_server* /*server*/) override { + return 0; + } +#endif // GPR_ANDROID + + void SetAuthMetadataProcessor( + const std::shared_ptr& /*processor*/) override { + GPR_ASSERT(false); + } + + private: + bool IsInsecure() const override { return true; } +}; + +} // namespace + +std::shared_ptr BinderServerCredentials() { + return std::shared_ptr(new BinderServerCredentialsImpl()); +} + +} // namespace experimental +} // namespace grpc diff --git a/src/core/ext/transport/binder/server/binder_server_credentials.h b/src/core/ext/transport/binder/server/binder_server_credentials.h new file mode 100644 index 00000000000..e8c326f042f --- /dev/null +++ b/src/core/ext/transport/binder/server/binder_server_credentials.h @@ -0,0 +1,35 @@ +// 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. + +#ifndef GRPC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_CREDENTIALS_H +#define GRPC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_CREDENTIALS_H + +#include + +#include + +namespace grpc { +namespace experimental { + +/// Builds Binder ServerCredentials. +/// +/// Calling \a ServerBuilder::AddListeningPort() with Binder ServerCredentials +/// in a non-Android environment will make the subsequent call to +/// \a ServerBuilder::BuildAndStart() returns a null pointer. +std::shared_ptr BinderServerCredentials(); + +} // namespace experimental +} // namespace grpc + +#endif // GRPC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_CREDENTIALS_H diff --git a/test/core/transport/binder/end2end/BUILD b/test/core/transport/binder/end2end/BUILD index c6dbf465c54..15b242e0a3b 100644 --- a/test/core/transport/binder/end2end/BUILD +++ b/test/core/transport/binder/end2end/BUILD @@ -110,3 +110,20 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) + +grpc_cc_test( + name = "binder_server_test", + srcs = ["binder_server_test.cc"], + external_deps = [ + "gtest", + ], + deps = [ + "//:grpc++", + "//src/core/ext/transport/binder/client:grpc_transport_binder_client_impl", + "//src/core/ext/transport/binder/server:grpc_transport_binder_server", + "//test/core/transport/binder/end2end:echo_service", + "//test/core/transport/binder/end2end:fake_binder", + "//test/core/util:grpc_test_util", + "//test/cpp/end2end:test_service_impl", + ], +) diff --git a/test/core/transport/binder/end2end/binder_server_test.cc b/test/core/transport/binder/end2end/binder_server_test.cc new file mode 100644 index 00000000000..f5b5774a4e0 --- /dev/null +++ b/test/core/transport/binder/end2end/binder_server_test.cc @@ -0,0 +1,211 @@ +// 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 "src/core/ext/transport/binder/server/binder_server.h" + +#include +#include +#include +#include +#include +#include + +#include "absl/memory/memory.h" +#include "src/core/ext/transport/binder/client/channel_create_impl.h" +#include "src/core/ext/transport/binder/server/binder_server.h" +#include "src/core/ext/transport/binder/server/binder_server_credentials.h" +#include "test/core/transport/binder/end2end/echo_service.h" +#include "test/core/transport/binder/end2end/fake_binder.h" +#include "test/core/util/test_config.h" +#include "test/cpp/end2end/test_service_impl.h" + +namespace grpc { +namespace testing { + +namespace { + +class BinderServerCredentialsImpl final : public ServerCredentials { + public: + int AddPortToServer(const std::string& addr, grpc_server* server) override { + return grpc_core::AddBinderPort( + addr, server, + [](grpc_binder::TransactionReceiver::OnTransactCb transact_cb) { + return absl::make_unique< + grpc_binder::end2end_testing::FakeTransactionReceiver>( + nullptr, std::move(transact_cb)); + }); + } + + void SetAuthMetadataProcessor( + const std::shared_ptr& /*processor*/) override { + GPR_ASSERT(false); + } + + private: + bool IsInsecure() const override { return true; } +}; + +} // namespace + +std::shared_ptr BinderServerCredentials() { + return std::shared_ptr(new BinderServerCredentialsImpl()); +} + +std::shared_ptr CreateBinderChannel( + std::unique_ptr endpoint_binder) { + grpc::internal::GrpcLibrary init_lib; + init_lib.init(); + + return grpc::CreateChannelInternal( + "", + grpc::internal::CreateChannelFromBinderImpl(std::move(endpoint_binder), + nullptr), + std::vector>()); +} + +} // namespace testing +} // namespace grpc + +namespace { + +class BinderServerTest : public ::testing::Test { + public: + BinderServerTest() { + grpc_binder::end2end_testing::g_transaction_processor = + new grpc_binder::end2end_testing::TransactionProcessor(); + } + ~BinderServerTest() override { + delete grpc_binder::end2end_testing::g_transaction_processor; + } + static void SetUpTestSuite() { + grpc_init(); + grpc_endpoint_binder_pool_init(); + } + static void TearDownTestSuite() { + grpc_endpoint_binder_pool_shutdown(); + grpc_shutdown(); + } +}; + +#ifndef GPR_ANDROID +TEST(BinderServerCredentialsTest, FailedInNonAndroidEnvironments) { + grpc::ServerBuilder server_builder; + grpc::testing::TestServiceImpl service; + server_builder.RegisterService(&service); + server_builder.AddListeningPort( + "binder://fail", grpc::experimental::BinderServerCredentials()); + EXPECT_EQ(server_builder.BuildAndStart(), nullptr); +} +#endif // !GPR_ANDROID + +TEST_F(BinderServerTest, BuildAndStart) { + grpc::ServerBuilder server_builder; + grpc_binder::end2end_testing::EchoServer service; + server_builder.RegisterService(&service); + server_builder.AddListeningPort("binder://example.service", + grpc::testing::BinderServerCredentials()); + std::unique_ptr server = server_builder.BuildAndStart(); + EXPECT_NE(grpc::experimental::binder::GetEndpointBinder("example.service"), + nullptr); + server->Shutdown(); + EXPECT_EQ(grpc::experimental::binder::GetEndpointBinder("example.service"), + nullptr); +} + +TEST_F(BinderServerTest, BuildAndStartFailed) { + grpc::ServerBuilder server_builder; + grpc_binder::end2end_testing::EchoServer service; + server_builder.RegisterService(&service); + // Error: binder address should begin with binder: + server_builder.AddListeningPort("localhost:12345", + grpc::testing::BinderServerCredentials()); + std::unique_ptr server = server_builder.BuildAndStart(); + EXPECT_EQ(server, nullptr); +} + +TEST_F(BinderServerTest, CreateChannelWithEndpointBinder) { + grpc::ServerBuilder server_builder; + grpc_binder::end2end_testing::EchoServer service; + server_builder.RegisterService(&service); + server_builder.AddListeningPort("binder://example.service", + grpc::testing::BinderServerCredentials()); + std::unique_ptr server = server_builder.BuildAndStart(); + void* raw_endpoint_binder = + grpc::experimental::binder::GetEndpointBinder("example.service"); + std::unique_ptr endpoint_binder = + absl::make_unique( + static_cast( + raw_endpoint_binder)); + std::shared_ptr channel = + grpc::testing::CreateBinderChannel(std::move(endpoint_binder)); + std::unique_ptr stub = + grpc_binder::end2end_testing::EchoService::NewStub(channel); + grpc_binder::end2end_testing::EchoRequest request; + grpc_binder::end2end_testing::EchoResponse response; + grpc::ClientContext context; + request.set_text("BinderServerBuilder"); + grpc::Status status = stub->EchoUnaryCall(&context, request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.text(), "BinderServerBuilder"); + server->Shutdown(); +} + +TEST_F(BinderServerTest, CreateChannelWithEndpointBinderMultipleConnections) { + grpc::ServerBuilder server_builder; + grpc_binder::end2end_testing::EchoServer service; + server_builder.RegisterService(&service); + server_builder.AddListeningPort( + "binder://example.service.multiple.connections", + grpc::testing::BinderServerCredentials()); + std::unique_ptr server = server_builder.BuildAndStart(); + void* raw_endpoint_binder = grpc::experimental::binder::GetEndpointBinder( + "example.service.multiple.connections"); + constexpr size_t kNumThreads = 128; + + auto thread_fn = [&](size_t id) { + std::unique_ptr endpoint_binder = + absl::make_unique( + static_cast( + raw_endpoint_binder)); + std::shared_ptr channel = + grpc::testing::CreateBinderChannel(std::move(endpoint_binder)); + std::unique_ptr stub = + grpc_binder::end2end_testing::EchoService::NewStub(channel); + grpc_binder::end2end_testing::EchoRequest request; + grpc_binder::end2end_testing::EchoResponse response; + grpc::ClientContext context; + request.set_text(absl::StrFormat("BinderServerBuilder-%d", id)); + grpc::Status status = stub->EchoUnaryCall(&context, request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.text(), absl::StrFormat("BinderServerBuilder-%d", id)); + }; + + std::vector threads(kNumThreads); + for (size_t i = 0; i < kNumThreads; ++i) { + threads[i] = std::thread(thread_fn, i); + } + for (auto& thr : threads) { + thr.join(); + } + server->Shutdown(); +} + +} // namespace + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc::testing::TestEnvironment env(argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/core/transport/binder/end2end/fake_binder.h b/test/core/transport/binder/end2end/fake_binder.h index bfb6835e585..68ddbb57c4f 100644 --- a/test/core/transport/binder/end2end/fake_binder.h +++ b/test/core/transport/binder/end2end/fake_binder.h @@ -182,9 +182,7 @@ class PersistentFakeTransactionReceiver { // other end of the tunnel by following the information in its endpoint. class FakeBinder final : public Binder { public: - explicit FakeBinder(FakeEndpoint* endpoint) : endpoint_(endpoint) { - endpoint_->owner = this; - } + explicit FakeBinder(FakeEndpoint* endpoint) : endpoint_(endpoint) {} void Initialize() override {} absl::Status PrepareTransaction() override { diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 5ddd0698df2..a7a67c32ca1 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -3429,6 +3429,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_server_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false,