Delete gRPC C++ Binder implementation

PiperOrigin-RevId: 685753453
pull/37878/head
AJ Heller 4 months ago committed by Copybara-Service
parent 3cdb133525
commit 4ffcdd4ab7
  1. 133
      BUILD
  2. 866
      CMakeLists.txt
  3. 1
      Makefile
  4. 1
      Package.swift
  5. 10
      WORKSPACE
  6. 765
      build_autogenerated.yaml
  7. 2
      config.m4
  8. 2
      config.w32
  9. 61
      gRPC-C++.podspec
  10. 1
      gRPC-Core.podspec
  11. 1
      grpc.gemspec
  12. 1
      include/grpc/support/port_platform.h
  13. 125
      include/grpcpp/create_channel_binder.h
  14. 43
      include/grpcpp/security/binder_credentials.h
  15. 82
      include/grpcpp/security/binder_security_policy.h
  16. 1
      package.xml
  17. 32
      src/core/BUILD
  18. 10
      src/core/ext/transport/binder/README.md
  19. 134
      src/core/ext/transport/binder/client/binder_connector.cc
  20. 41
      src/core/ext/transport/binder/client/binder_connector.h
  21. 231
      src/core/ext/transport/binder/client/channel_create.cc
  22. 93
      src/core/ext/transport/binder/client/channel_create_impl.cc
  23. 42
      src/core/ext/transport/binder/client/channel_create_impl.h
  24. 69
      src/core/ext/transport/binder/client/connection_id_generator.cc
  25. 50
      src/core/ext/transport/binder/client/connection_id_generator.h
  26. 114
      src/core/ext/transport/binder/client/endpoint_binder_pool.cc
  27. 64
      src/core/ext/transport/binder/client/endpoint_binder_pool.h
  28. 138
      src/core/ext/transport/binder/client/jni_utils.cc
  29. 57
      src/core/ext/transport/binder/client/jni_utils.h
  30. 47
      src/core/ext/transport/binder/client/security_policy_setting.cc
  31. 49
      src/core/ext/transport/binder/client/security_policy_setting.h
  32. 0
      src/core/ext/transport/binder/java/WORKSPACE
  33. 30
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/BUILD
  34. 104
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/GrpcBinderConnection.java
  35. 40
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/GrpcCppServerBuilder.java
  36. 71
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/NativeConnectionHelper.java
  37. 106
      src/core/ext/transport/binder/security_policy/binder_security_policy.cc
  38. 40
      src/core/ext/transport/binder/security_policy/security_policy.h
  39. 249
      src/core/ext/transport/binder/server/binder_server.cc
  40. 65
      src/core/ext/transport/binder/server/binder_server.h
  41. 71
      src/core/ext/transport/binder/server/binder_server_credentials.cc
  42. 117
      src/core/ext/transport/binder/transport/binder_stream.h
  43. 758
      src/core/ext/transport/binder/transport/binder_transport.cc
  44. 119
      src/core/ext/transport/binder/transport/binder_transport.h
  45. 76
      src/core/ext/transport/binder/utils/binder_auto_utils.h
  46. 218
      src/core/ext/transport/binder/utils/ndk_binder.cc
  47. 107
      src/core/ext/transport/binder/utils/ndk_binder.h
  48. 70
      src/core/ext/transport/binder/utils/transport_stream_receiver.h
  49. 257
      src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc
  50. 112
      src/core/ext/transport/binder/utils/transport_stream_receiver_impl.h
  51. 104
      src/core/ext/transport/binder/wire_format/binder.h
  52. 308
      src/core/ext/transport/binder/wire_format/binder_android.cc
  53. 121
      src/core/ext/transport/binder/wire_format/binder_android.h
  54. 29
      src/core/ext/transport/binder/wire_format/binder_constants.cc
  55. 43
      src/core/ext/transport/binder/wire_format/binder_constants.h
  56. 33
      src/core/ext/transport/binder/wire_format/transaction.cc
  57. 106
      src/core/ext/transport/binder/wire_format/transaction.h
  58. 38
      src/core/ext/transport/binder/wire_format/wire_reader.h
  59. 450
      src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
  60. 158
      src/core/ext/transport/binder/wire_format/wire_reader_impl.h
  61. 393
      src/core/ext/transport/binder/wire_format/wire_writer.cc
  62. 126
      src/core/ext/transport/binder/wire_format/wire_writer.h
  63. 6
      src/core/plugin_registry/grpc_plugin_registry.cc
  64. 9
      src/core/resolver/binder/README.md
  65. 151
      src/core/resolver/binder/binder_resolver.cc
  66. 1
      src/python/grpcio/grpc_core_dependencies.py
  67. 16
      test/core/resolver/BUILD
  68. 216
      test/core/resolver/binder_resolver_test.cc
  69. 133
      test/core/transport/binder/BUILD
  70. 729
      test/core/transport/binder/binder_transport_test.cc
  71. 119
      test/core/transport/binder/end2end/BUILD
  72. 243
      test/core/transport/binder/end2end/binder_server_test.cc
  73. 566
      test/core/transport/binder/end2end/end2end_binder_transport_test.cc
  74. 276
      test/core/transport/binder/end2end/fake_binder.cc
  75. 307
      test/core/transport/binder/end2end/fake_binder.h
  76. 349
      test/core/transport/binder/end2end/fake_binder_test.cc
  77. 101
      test/core/transport/binder/end2end/fuzzers/BUILD
  78. 0
      test/core/transport/binder/end2end/fuzzers/binder_transport_client_fuzzer_corpus/empty
  79. 81
      test/core/transport/binder/end2end/fuzzers/binder_transport_fuzzer.proto
  80. 0
      test/core/transport/binder/end2end/fuzzers/binder_transport_server_fuzzer_corpus/empty
  81. 17
      test/core/transport/binder/end2end/fuzzers/client.proto
  82. 158
      test/core/transport/binder/end2end/fuzzers/client_fuzzer.cc
  83. 157
      test/core/transport/binder/end2end/fuzzers/fuzzer_utils.cc
  84. 152
      test/core/transport/binder/end2end/fuzzers/fuzzer_utils.h
  85. 17
      test/core/transport/binder/end2end/fuzzers/server.proto
  86. 132
      test/core/transport/binder/end2end/fuzzers/server_fuzzer.cc
  87. 133
      test/core/transport/binder/end2end/testing_channel_create.cc
  88. 41
      test/core/transport/binder/end2end/testing_channel_create.h
  89. 74
      test/core/transport/binder/endpoint_binder_pool_test.cc
  90. 55
      test/core/transport/binder/mock_objects.cc
  91. 121
      test/core/transport/binder/mock_objects.h
  92. 287
      test/core/transport/binder/transport_stream_receiver_test.cc
  93. 376
      test/core/transport/binder/wire_reader_test.cc
  94. 265
      test/core/transport/binder/wire_writer_test.cc
  95. 3
      tools/doxygen/Doxyfile.c++
  96. 42
      tools/doxygen/Doxyfile.c++.internal
  97. 3
      tools/doxygen/Doxyfile.core.internal
  98. 192
      tools/run_tests/generated/tests.json

133
BUILD

@ -75,17 +75,6 @@ config_setting(
flag_values = {":disable_grpc_rls": "true"},
)
# When gRPC is build as shared library, binder transport code might still
# get included even when user's code does not depend on it. In that case
# --define=grpc_no_binder=true can be used to disable binder transport
# related code to reduce binary size.
# For users using build system other than bazel, they can define
# GRPC_NO_BINDER to achieve the same effect.
config_setting(
name = "grpc_no_binder_define",
values = {"define": "grpc_no_binder=true"},
)
config_setting(
name = "android",
values = {"crosstool_top": "//external:android/crosstool"},
@ -136,15 +125,6 @@ selects.config_setting_group(
],
)
selects.config_setting_group(
name = "grpc_no_binder",
match_any = [
":grpc_no_binder_define",
# We do not need binder on ios.
":ios",
],
)
selects.config_setting_group(
name = "grpc_no_rls",
match_any = [
@ -857,7 +837,6 @@ grpc_cc_library(
"//src/core:grpc_lb_policy_weighted_target",
"//src/core:grpc_channel_idle_filter",
"//src/core:grpc_message_size_filter",
"//src/core:grpc_resolver_binder",
"grpc_resolver_dns_ares",
"grpc_resolver_fake",
"//src/core:grpc_resolver_dns_native",
@ -943,12 +922,6 @@ grpc_cc_library(
"grpc++_xds_server",
],
},
{
"grpc_no_binder": [],
"//conditions:default": [
"grpc++_binder",
],
},
],
tags = ["nofixdeps"],
visibility = ["@grpc:public"],
@ -1079,112 +1052,6 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc++_binder",
srcs = [
"//src/core:ext/transport/binder/client/binder_connector.cc",
"//src/core:ext/transport/binder/client/channel_create.cc",
"//src/core:ext/transport/binder/client/channel_create_impl.cc",
"//src/core:ext/transport/binder/client/connection_id_generator.cc",
"//src/core:ext/transport/binder/client/endpoint_binder_pool.cc",
"//src/core:ext/transport/binder/client/jni_utils.cc",
"//src/core:ext/transport/binder/client/security_policy_setting.cc",
"//src/core:ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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",
],
hdrs = [
"//src/core:ext/transport/binder/client/binder_connector.h",
"//src/core:ext/transport/binder/client/channel_create_impl.h",
"//src/core:ext/transport/binder/client/connection_id_generator.h",
"//src/core:ext/transport/binder/client/endpoint_binder_pool.h",
"//src/core:ext/transport/binder/client/jni_utils.h",
"//src/core:ext/transport/binder/client/security_policy_setting.h",
"//src/core:ext/transport/binder/server/binder_server.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/binder_auto_utils.h",
"//src/core:ext/transport/binder/utils/ndk_binder.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",
],
defines = select({
"grpc_no_binder": ["GRPC_NO_BINDER"],
"//conditions:default": [],
}),
external_deps = [
"absl/base:core_headers",
"absl/cleanup",
"absl/container:flat_hash_map",
"absl/functional:any_invocable",
"absl/hash",
"absl/log:check",
"absl/log:log",
"absl/memory",
"absl/meta:type_traits",
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/synchronization",
"absl/time",
"absl/types:variant",
],
language = "c++",
public_hdrs = [
"include/grpcpp/security/binder_security_policy.h",
"include/grpcpp/create_channel_binder.h",
"include/grpcpp/security/binder_credentials.h",
],
tags = ["nofixdeps"],
deps = [
"channel",
"channel_create",
"config",
"debug_location",
"exec_ctx",
"gpr",
"gpr_platform",
"grpc",
"grpc++_base",
"grpc_base",
"grpc_client_channel",
"grpc_public_hdrs",
"orphanable",
"ref_counted_ptr",
"server",
"//src/core:arena",
"//src/core:channel_args",
"//src/core:channel_args_preconditioning",
"//src/core:channel_stack_type",
"//src/core:default_event_engine",
"//src/core:error_utils",
"//src/core:iomgr_fwd",
"//src/core:iomgr_port",
"//src/core:metadata_batch",
"//src/core:notification",
"//src/core:slice",
"//src/core:slice_refcount",
"//src/core:status_helper",
"//src/core:subchannel_connector",
"//src/core:transport_fwd",
],
)
grpc_cc_library(
name = "grpc++_xds_client",
srcs = [

866
CMakeLists.txt generated

@ -1167,9 +1167,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx bin_decoder_test)
add_dependencies(buildtests_cxx bin_encoder_test)
add_dependencies(buildtests_cxx binary_metadata_test)
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)
add_dependencies(buildtests_cxx blackboard_test)
add_dependencies(buildtests_cxx buffer_list_test)
@ -1285,12 +1282,8 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx dump_args_test)
add_dependencies(buildtests_cxx duplicate_header_bad_client_test)
add_dependencies(buildtests_cxx empty_batch_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx end2end_binder_transport_test)
endif()
add_dependencies(buildtests_cxx end2end_test)
add_dependencies(buildtests_cxx endpoint_addresses_test)
add_dependencies(buildtests_cxx endpoint_binder_pool_test)
add_dependencies(buildtests_cxx endpoint_config_test)
add_dependencies(buildtests_cxx endpoint_pair_test)
add_dependencies(buildtests_cxx env_test)
@ -1310,7 +1303,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx experiments_tag_test)
add_dependencies(buildtests_cxx experiments_test)
add_dependencies(buildtests_cxx factory_test)
add_dependencies(buildtests_cxx fake_binder_test)
add_dependencies(buildtests_cxx fake_resolver_test)
add_dependencies(buildtests_cxx fake_transport_security_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -1742,7 +1734,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx trailing_metadata_test)
add_dependencies(buildtests_cxx transport_security_common_api_test)
add_dependencies(buildtests_cxx transport_security_test)
add_dependencies(buildtests_cxx transport_stream_receiver_test)
add_dependencies(buildtests_cxx try_join_test)
add_dependencies(buildtests_cxx try_seq_metadata_test)
add_dependencies(buildtests_cxx try_seq_test)
@ -1767,8 +1758,6 @@ if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX OR _gRPC_PLATFORM_WINDOWS)
add_dependencies(buildtests_cxx windows_endpoint_test)
endif()
add_dependencies(buildtests_cxx wire_reader_test)
add_dependencies(buildtests_cxx wire_writer_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx work_serializer_test)
endif()
@ -2758,7 +2747,6 @@ add_library(grpc
src/core/load_balancing/xds/xds_wrr_locality.cc
src/core/plugin_registry/grpc_plugin_registry.cc
src/core/plugin_registry/grpc_plugin_registry_extra.cc
src/core/resolver/binder/binder_resolver.cc
src/core/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
@ -3525,7 +3513,6 @@ add_library(grpc_unsecure
src/core/load_balancing/weighted_target/weighted_target.cc
src/core/plugin_registry/grpc_plugin_registry.cc
src/core/plugin_registry/grpc_plugin_registry_noextra.cc
src/core/resolver/binder/binder_resolver.cc
src/core/resolver/dns/c_ares/dns_resolver_ares.cc
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
@ -4399,24 +4386,6 @@ endif()
endif()
add_library(grpc++
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
@ -4598,7 +4567,6 @@ foreach(_hdr
include/grpcpp/client_context.h
include/grpcpp/completion_queue.h
include/grpcpp/create_channel.h
include/grpcpp/create_channel_binder.h
include/grpcpp/create_channel_posix.h
include/grpcpp/ext/call_metric_recorder.h
include/grpcpp/ext/health_check_service_server_builder_option.h
@ -4690,8 +4658,6 @@ foreach(_hdr
include/grpcpp/security/auth_context.h
include/grpcpp/security/auth_metadata_processor.h
include/grpcpp/security/authorization_policy_provider.h
include/grpcpp/security/binder_credentials.h
include/grpcpp/security/binder_security_policy.h
include/grpcpp/security/credentials.h
include/grpcpp/security/server_credentials.h
include/grpcpp/security/tls_certificate_provider.h
@ -8381,220 +8347,6 @@ target_link_libraries(binary_metadata_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(binder_resolver_test
test/core/resolver/binder_resolver_test.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(binder_resolver_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(binder_resolver_test PUBLIC cxx_std_14)
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_ALLTARGETS_LIBRARIES}
gtest
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
${_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}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/core/transport/binder/end2end/binder_server_test.cc
test/core/transport/binder/end2end/fake_binder.cc
test/cpp/end2end/test_service_impl.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(binder_server_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
"GRPCXX_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(binder_server_test PUBLIC cxx_std_14)
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_ALLTARGETS_LIBRARIES}
gtest
grpc++_test_util
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(binder_transport_test
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
src/cpp/client/client_interceptor.cc
src/cpp/client/client_stats_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/global_callback_hook.cc
src/cpp/client/insecure_credentials.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/auth_property_iterator.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_certificate_provider.cc
src/cpp/common/tls_certificate_verifier.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/backend_metric_recorder.cc
src/cpp/server/channel_argument_option.cc
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/external_connection_acceptor_impl.cc
src/cpp/server/health/default_health_check_service.cc
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/server/server_credentials.cc
src/cpp/server/server_posix.cc
src/cpp/thread_manager/thread_manager.cc
src/cpp/util/byte_buffer_cc.cc
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
test/core/transport/binder/binder_transport_test.cc
test/core/transport/binder/mock_objects.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(binder_transport_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(binder_transport_test PUBLIC cxx_std_14)
target_include_directories(binder_transport_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_transport_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::absl_check
absl::absl_log
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -13511,70 +13263,6 @@ target_link_libraries(empty_batch_test
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
add_executable(end2end_binder_transport_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}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/orca_load_report.grpc.pb.h
test/core/transport/binder/end2end/end2end_binder_transport_test.cc
test/core/transport/binder/end2end/fake_binder.cc
test/core/transport/binder/end2end/testing_channel_create.cc
test/cpp/end2end/test_service_impl.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(end2end_binder_transport_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
"GRPCXX_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(end2end_binder_transport_test PUBLIC cxx_std_14)
target_include_directories(end2end_binder_transport_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(end2end_binder_transport_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
grpc++_test_util
)
endif()
endif()
if(gRPC_BUILD_TESTS)
@ -13682,117 +13370,6 @@ target_link_libraries(endpoint_addresses_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(endpoint_binder_pool_test
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
src/cpp/client/client_interceptor.cc
src/cpp/client/client_stats_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/global_callback_hook.cc
src/cpp/client/insecure_credentials.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/auth_property_iterator.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_certificate_provider.cc
src/cpp/common/tls_certificate_verifier.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/backend_metric_recorder.cc
src/cpp/server/channel_argument_option.cc
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/external_connection_acceptor_impl.cc
src/cpp/server/health/default_health_check_service.cc
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/server/server_credentials.cc
src/cpp/server/server_posix.cc
src/cpp/thread_manager/thread_manager.cc
src/cpp/util/byte_buffer_cc.cc
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
test/core/transport/binder/endpoint_binder_pool_test.cc
test/core/transport/binder/mock_objects.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(endpoint_binder_pool_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(endpoint_binder_pool_test PUBLIC cxx_std_14)
target_include_directories(endpoint_binder_pool_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(endpoint_binder_pool_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::absl_check
absl::absl_log
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -14538,117 +14115,6 @@ target_link_libraries(factory_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(fake_binder_test
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
src/cpp/client/client_interceptor.cc
src/cpp/client/client_stats_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/global_callback_hook.cc
src/cpp/client/insecure_credentials.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/auth_property_iterator.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_certificate_provider.cc
src/cpp/common/tls_certificate_verifier.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/backend_metric_recorder.cc
src/cpp/server/channel_argument_option.cc
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/external_connection_acceptor_impl.cc
src/cpp/server/health/default_health_check_service.cc
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/server/server_credentials.cc
src/cpp/server/server_posix.cc
src/cpp/thread_manager/thread_manager.cc
src/cpp/util/byte_buffer_cc.cc
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
test/core/transport/binder/end2end/fake_binder.cc
test/core/transport/binder/end2end/fake_binder_test.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(fake_binder_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(fake_binder_test PUBLIC cxx_std_14)
target_include_directories(fake_binder_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(fake_binder_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::absl_check
absl::absl_log
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -32793,116 +32259,6 @@ target_link_libraries(transport_security_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(transport_stream_receiver_test
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
src/cpp/client/client_interceptor.cc
src/cpp/client/client_stats_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/global_callback_hook.cc
src/cpp/client/insecure_credentials.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/auth_property_iterator.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_certificate_provider.cc
src/cpp/common/tls_certificate_verifier.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/backend_metric_recorder.cc
src/cpp/server/channel_argument_option.cc
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/external_connection_acceptor_impl.cc
src/cpp/server/health/default_health_check_service.cc
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/server/server_credentials.cc
src/cpp/server/server_posix.cc
src/cpp/thread_manager/thread_manager.cc
src/cpp/util/byte_buffer_cc.cc
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
test/core/transport/binder/transport_stream_receiver_test.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(transport_stream_receiver_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(transport_stream_receiver_test PUBLIC cxx_std_14)
target_include_directories(transport_stream_receiver_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(transport_stream_receiver_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::absl_check
absl::absl_log
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -33680,228 +33036,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX OR _gRPC_PLATFORM_WINDOWS)
endif()
endif()
if(gRPC_BUILD_TESTS)
add_executable(wire_reader_test
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
src/cpp/client/client_interceptor.cc
src/cpp/client/client_stats_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/global_callback_hook.cc
src/cpp/client/insecure_credentials.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/auth_property_iterator.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_certificate_provider.cc
src/cpp/common/tls_certificate_verifier.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/backend_metric_recorder.cc
src/cpp/server/channel_argument_option.cc
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/external_connection_acceptor_impl.cc
src/cpp/server/health/default_health_check_service.cc
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/server/server_credentials.cc
src/cpp/server/server_posix.cc
src/cpp/thread_manager/thread_manager.cc
src/cpp/util/byte_buffer_cc.cc
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
test/core/transport/binder/mock_objects.cc
test/core/transport/binder/wire_reader_test.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(wire_reader_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(wire_reader_test PUBLIC cxx_std_14)
target_include_directories(wire_reader_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(wire_reader_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::absl_check
absl::absl_log
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(wire_writer_test
src/core/ext/transport/binder/client/binder_connector.cc
src/core/ext/transport/binder/client/channel_create.cc
src/core/ext/transport/binder/client/channel_create_impl.cc
src/core/ext/transport/binder/client/connection_id_generator.cc
src/core/ext/transport/binder/client/endpoint_binder_pool.cc
src/core/ext/transport/binder/client/jni_utils.cc
src/core/ext/transport/binder/client/security_policy_setting.cc
src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
src/cpp/client/call_credentials.cc
src/cpp/client/channel_cc.cc
src/cpp/client/channel_credentials.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
src/cpp/client/client_interceptor.cc
src/cpp/client/client_stats_interceptor.cc
src/cpp/client/create_channel.cc
src/cpp/client/create_channel_internal.cc
src/cpp/client/create_channel_posix.cc
src/cpp/client/global_callback_hook.cc
src/cpp/client/insecure_credentials.cc
src/cpp/client/secure_credentials.cc
src/cpp/common/alarm.cc
src/cpp/common/auth_property_iterator.cc
src/cpp/common/channel_arguments.cc
src/cpp/common/completion_queue_cc.cc
src/cpp/common/resource_quota_cc.cc
src/cpp/common/rpc_method.cc
src/cpp/common/secure_auth_context.cc
src/cpp/common/secure_create_auth_context.cc
src/cpp/common/tls_certificate_provider.cc
src/cpp/common/tls_certificate_verifier.cc
src/cpp/common/tls_credentials_options.cc
src/cpp/common/validate_service_config.cc
src/cpp/common/version_cc.cc
src/cpp/server/async_generic_service.cc
src/cpp/server/backend_metric_recorder.cc
src/cpp/server/channel_argument_option.cc
src/cpp/server/create_default_thread_pool.cc
src/cpp/server/external_connection_acceptor_impl.cc
src/cpp/server/health/default_health_check_service.cc
src/cpp/server/health/health_check_service.cc
src/cpp/server/health/health_check_service_server_builder_option.cc
src/cpp/server/insecure_server_credentials.cc
src/cpp/server/secure_server_credentials.cc
src/cpp/server/server_builder.cc
src/cpp/server/server_callback.cc
src/cpp/server/server_cc.cc
src/cpp/server/server_context.cc
src/cpp/server/server_credentials.cc
src/cpp/server/server_posix.cc
src/cpp/thread_manager/thread_manager.cc
src/cpp/util/byte_buffer_cc.cc
src/cpp/util/status.cc
src/cpp/util/string_ref.cc
src/cpp/util/time_cc.cc
test/core/transport/binder/mock_objects.cc
test/core/transport/binder/wire_writer_test.cc
)
if(WIN32 AND MSVC)
if(BUILD_SHARED_LIBS)
target_compile_definitions(wire_writer_test
PRIVATE
"GPR_DLL_IMPORTS"
"GRPC_DLL_IMPORTS"
)
endif()
endif()
target_compile_features(wire_writer_test PUBLIC cxx_std_14)
target_include_directories(wire_writer_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(wire_writer_test
${_gRPC_ALLTARGETS_LIBRARIES}
gtest
absl::absl_check
absl::absl_log
${_gRPC_PROTOBUF_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)

1
Makefile generated

@ -1358,7 +1358,6 @@ LIBGRPC_SRC = \
src/core/load_balancing/xds/xds_wrr_locality.cc \
src/core/plugin_registry/grpc_plugin_registry.cc \
src/core/plugin_registry/grpc_plugin_registry_extra.cc \
src/core/resolver/binder/binder_resolver.cc \
src/core/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \

1
Package.swift generated

@ -1709,7 +1709,6 @@ let package = Package(
"src/core/load_balancing/xds/xds_wrr_locality.cc",
"src/core/plugin_registry/grpc_plugin_registry.cc",
"src/core/plugin_registry/grpc_plugin_registry_extra.cc",
"src/core/resolver/binder/binder_resolver.cc",
"src/core/resolver/dns/c_ares/dns_resolver_ares.cc",
"src/core/resolver/dns/c_ares/dns_resolver_ares.h",
"src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h",

@ -56,16 +56,6 @@ android_ndk_repository(name = "androidndk")
# here, because the toolchain rule fails when $ANDROID_NDK_HOME is not set.
# Use `--extra_toolchains=@androidndk//:all` to manually register it when building for Android.
# Prevents bazel's '...' expansion from including the following folder.
# This is required because the BUILD file in the following folder
# will trigger bazel failure when Android SDK is not configured.
# The targets in the following folder need to be included in APK and will
# be invoked by binder transport implementation through JNI.
local_repository(
name = "binder_transport_android_helper",
path = "src/core/ext/transport/binder/java",
)
# Prevents bazel's '...' expansion from including the following folder.
# This is required to avoid triggering "Unable to find package for @rules_fuzzing//fuzzing:cc_defs.bzl"
# error.

@ -1965,7 +1965,6 @@ libs:
- src/core/load_balancing/xds/xds_wrr_locality.cc
- src/core/plugin_registry/grpc_plugin_registry.cc
- src/core/plugin_registry/grpc_plugin_registry_extra.cc
- src/core/resolver/binder/binder_resolver.cc
- src/core/resolver/dns/c_ares/dns_resolver_ares.cc
- src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
- src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
@ -3084,7 +3083,6 @@ libs:
- src/core/load_balancing/weighted_target/weighted_target.cc
- src/core/plugin_registry/grpc_plugin_registry.cc
- src/core/plugin_registry/grpc_plugin_registry_noextra.cc
- src/core/resolver/binder/binder_resolver.cc
- src/core/resolver/dns/c_ares/dns_resolver_ares.cc
- src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc
- src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc
@ -3770,7 +3768,6 @@ libs:
- include/grpcpp/client_context.h
- include/grpcpp/completion_queue.h
- include/grpcpp/create_channel.h
- include/grpcpp/create_channel_binder.h
- include/grpcpp/create_channel_posix.h
- include/grpcpp/ext/call_metric_recorder.h
- include/grpcpp/ext/health_check_service_server_builder_option.h
@ -3862,8 +3859,6 @@ libs:
- include/grpcpp/security/auth_context.h
- include/grpcpp/security/auth_metadata_processor.h
- include/grpcpp/security/authorization_policy_provider.h
- include/grpcpp/security/binder_credentials.h
- include/grpcpp/security/binder_security_policy.h
- include/grpcpp/security/credentials.h
- include/grpcpp/security/server_credentials.h
- include/grpcpp/security/tls_certificate_provider.h
@ -3902,26 +3897,6 @@ libs:
- include/grpcpp/version_info.h
- include/grpcpp/xds_server_builder.h
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/core/xds/grpc/xds_enabled_server.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
@ -3935,24 +3910,6 @@ libs:
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
@ -6141,146 +6098,6 @@ targets:
- grpc_authorization_provider
- grpc_unsecure
- grpc_test_util
- name: binder_resolver_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/resolver/binder_resolver_test.cc
deps:
- gtest
- grpc_test_util
- name: binder_server_test
gtest: true
build: test
language: c++
headers:
- 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
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/core/transport/binder/end2end/binder_server_test.cc
- test/core/transport/binder/end2end/fake_binder.cc
- test/cpp/end2end/test_service_impl.cc
deps:
- gtest
- grpc++_test_util
- name: binder_transport_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/server/backend_metric_recorder.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/external_connection_acceptor_impl.h
- src/cpp/server/health/default_health_check_service.h
- src/cpp/server/secure_server_credentials.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
- test/core/transport/binder/mock_objects.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
- src/cpp/client/client_interceptor.cc
- src/cpp/client/client_stats_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/global_callback_hook.cc
- src/cpp/client/insecure_credentials.cc
- src/cpp/client/secure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/auth_property_iterator.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_certificate_provider.cc
- src/cpp/common/tls_certificate_verifier.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/backend_metric_recorder.cc
- src/cpp/server/channel_argument_option.cc
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/external_connection_acceptor_impl.cc
- src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
- src/cpp/server/server_builder.cc
- src/cpp/server/server_callback.cc
- src/cpp/server/server_cc.cc
- src/cpp/server/server_context.cc
- src/cpp/server/server_credentials.cc
- src/cpp/server/server_posix.cc
- src/cpp/thread_manager/thread_manager.cc
- src/cpp/util/byte_buffer_cc.cc
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
- test/core/transport/binder/binder_transport_test.cc
- test/core/transport/binder/mock_objects.cc
deps:
- gtest
- absl/log:absl_check
- absl/log:absl_log
- protobuf
- grpc_test_util
uses_polling: false
- name: bitset_test
gtest: true
build: test
@ -9654,30 +9471,6 @@ targets:
- grpc_authorization_provider
- grpc_unsecure
- grpc_test_util
- name: end2end_binder_transport_test
gtest: true
build: test
run: false
language: c++
headers:
- test/core/transport/binder/end2end/fake_binder.h
- test/core/transport/binder/end2end/testing_channel_create.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
- src/proto/grpc/testing/xds/v3/orca_load_report.proto
- test/core/transport/binder/end2end/end2end_binder_transport_test.cc
- test/core/transport/binder/end2end/fake_binder.cc
- test/core/transport/binder/end2end/testing_channel_create.cc
- test/cpp/end2end/test_service_impl.cc
deps:
- gtest
- grpc++_test_util
platforms:
- linux
- posix
- name: end2end_test
gtest: true
build: test
@ -9709,118 +9502,6 @@ targets:
- gtest
- grpc_test_util
uses_polling: false
- name: endpoint_binder_pool_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/server/backend_metric_recorder.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/external_connection_acceptor_impl.h
- src/cpp/server/health/default_health_check_service.h
- src/cpp/server/secure_server_credentials.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
- test/core/transport/binder/mock_objects.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
- src/cpp/client/client_interceptor.cc
- src/cpp/client/client_stats_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/global_callback_hook.cc
- src/cpp/client/insecure_credentials.cc
- src/cpp/client/secure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/auth_property_iterator.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_certificate_provider.cc
- src/cpp/common/tls_certificate_verifier.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/backend_metric_recorder.cc
- src/cpp/server/channel_argument_option.cc
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/external_connection_acceptor_impl.cc
- src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
- src/cpp/server/server_builder.cc
- src/cpp/server/server_callback.cc
- src/cpp/server/server_cc.cc
- src/cpp/server/server_context.cc
- src/cpp/server/server_credentials.cc
- src/cpp/server/server_posix.cc
- src/cpp/thread_manager/thread_manager.cc
- src/cpp/util/byte_buffer_cc.cc
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
- test/core/transport/binder/endpoint_binder_pool_test.cc
- test/core/transport/binder/mock_objects.cc
deps:
- gtest
- absl/log:absl_check
- absl/log:absl_log
- protobuf
- grpc_test_util
uses_polling: false
- name: endpoint_config_test
gtest: true
build: test
@ -10185,118 +9866,6 @@ targets:
deps:
- gtest
- grpc_test_util_unsecure
- name: fake_binder_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/server/backend_metric_recorder.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/external_connection_acceptor_impl.h
- src/cpp/server/health/default_health_check_service.h
- src/cpp/server/secure_server_credentials.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
- test/core/transport/binder/end2end/fake_binder.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
- src/cpp/client/client_interceptor.cc
- src/cpp/client/client_stats_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/global_callback_hook.cc
- src/cpp/client/insecure_credentials.cc
- src/cpp/client/secure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/auth_property_iterator.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_certificate_provider.cc
- src/cpp/common/tls_certificate_verifier.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/backend_metric_recorder.cc
- src/cpp/server/channel_argument_option.cc
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/external_connection_acceptor_impl.cc
- src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
- src/cpp/server/server_builder.cc
- src/cpp/server/server_callback.cc
- src/cpp/server/server_cc.cc
- src/cpp/server/server_context.cc
- src/cpp/server/server_credentials.cc
- src/cpp/server/server_posix.cc
- src/cpp/thread_manager/thread_manager.cc
- src/cpp/util/byte_buffer_cc.cc
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
- test/core/transport/binder/end2end/fake_binder.cc
- test/core/transport/binder/end2end/fake_binder_test.cc
deps:
- gtest
- absl/log:absl_check
- absl/log:absl_log
- protobuf
- grpc_test_util
uses_polling: false
- name: fake_resolver_test
gtest: true
build: test
@ -20658,116 +20227,6 @@ targets:
deps:
- gtest
- grpc_test_util
- name: transport_stream_receiver_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/server/backend_metric_recorder.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/external_connection_acceptor_impl.h
- src/cpp/server/health/default_health_check_service.h
- src/cpp/server/secure_server_credentials.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
- src/cpp/client/client_interceptor.cc
- src/cpp/client/client_stats_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/global_callback_hook.cc
- src/cpp/client/insecure_credentials.cc
- src/cpp/client/secure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/auth_property_iterator.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_certificate_provider.cc
- src/cpp/common/tls_certificate_verifier.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/backend_metric_recorder.cc
- src/cpp/server/channel_argument_option.cc
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/external_connection_acceptor_impl.cc
- src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
- src/cpp/server/server_builder.cc
- src/cpp/server/server_callback.cc
- src/cpp/server/server_cc.cc
- src/cpp/server/server_context.cc
- src/cpp/server/server_credentials.cc
- src/cpp/server/server_posix.cc
- src/cpp/thread_manager/thread_manager.cc
- src/cpp/util/byte_buffer_cc.cc
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
- test/core/transport/binder/transport_stream_receiver_test.cc
deps:
- gtest
- absl/log:absl_check
- absl/log:absl_log
- protobuf
- grpc_test_util
uses_polling: false
- name: try_join_test
gtest: true
build: test
@ -21077,230 +20536,6 @@ targets:
- posix
- windows
uses_polling: false
- name: wire_reader_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/server/backend_metric_recorder.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/external_connection_acceptor_impl.h
- src/cpp/server/health/default_health_check_service.h
- src/cpp/server/secure_server_credentials.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
- test/core/transport/binder/mock_objects.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
- src/cpp/client/client_interceptor.cc
- src/cpp/client/client_stats_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/global_callback_hook.cc
- src/cpp/client/insecure_credentials.cc
- src/cpp/client/secure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/auth_property_iterator.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_certificate_provider.cc
- src/cpp/common/tls_certificate_verifier.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/backend_metric_recorder.cc
- src/cpp/server/channel_argument_option.cc
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/external_connection_acceptor_impl.cc
- src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
- src/cpp/server/server_builder.cc
- src/cpp/server/server_callback.cc
- src/cpp/server/server_cc.cc
- src/cpp/server/server_context.cc
- src/cpp/server/server_credentials.cc
- src/cpp/server/server_posix.cc
- src/cpp/thread_manager/thread_manager.cc
- src/cpp/util/byte_buffer_cc.cc
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
- test/core/transport/binder/mock_objects.cc
- test/core/transport/binder/wire_reader_test.cc
deps:
- gtest
- absl/log:absl_check
- absl/log:absl_log
- protobuf
- grpc_test_util
uses_polling: false
- name: wire_writer_test
gtest: true
build: test
language: c++
headers:
- src/core/ext/transport/binder/client/binder_connector.h
- src/core/ext/transport/binder/client/channel_create_impl.h
- src/core/ext/transport/binder/client/connection_id_generator.h
- src/core/ext/transport/binder/client/endpoint_binder_pool.h
- src/core/ext/transport/binder/client/jni_utils.h
- src/core/ext/transport/binder/client/security_policy_setting.h
- src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h
- src/core/ext/transport/binder/utils/ndk_binder.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
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
- src/cpp/common/secure_auth_context.h
- src/cpp/server/backend_metric_recorder.h
- src/cpp/server/dynamic_thread_pool.h
- src/cpp/server/external_connection_acceptor_impl.h
- src/cpp/server/health/default_health_check_service.h
- src/cpp/server/secure_server_credentials.h
- src/cpp/server/thread_pool_interface.h
- src/cpp/thread_manager/thread_manager.h
- test/core/transport/binder/mock_objects.h
src:
- src/core/ext/transport/binder/client/binder_connector.cc
- src/core/ext/transport/binder/client/channel_create.cc
- src/core/ext/transport/binder/client/channel_create_impl.cc
- src/core/ext/transport/binder/client/connection_id_generator.cc
- src/core/ext/transport/binder/client/endpoint_binder_pool.cc
- src/core/ext/transport/binder/client/jni_utils.cc
- src/core/ext/transport/binder/client/security_policy_setting.cc
- src/core/ext/transport/binder/security_policy/binder_security_policy.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/ndk_binder.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
- src/cpp/client/call_credentials.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/channel_credentials.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
- src/cpp/client/client_interceptor.cc
- src/cpp/client/client_stats_interceptor.cc
- src/cpp/client/create_channel.cc
- src/cpp/client/create_channel_internal.cc
- src/cpp/client/create_channel_posix.cc
- src/cpp/client/global_callback_hook.cc
- src/cpp/client/insecure_credentials.cc
- src/cpp/client/secure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/auth_property_iterator.cc
- src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue_cc.cc
- src/cpp/common/resource_quota_cc.cc
- src/cpp/common/rpc_method.cc
- src/cpp/common/secure_auth_context.cc
- src/cpp/common/secure_create_auth_context.cc
- src/cpp/common/tls_certificate_provider.cc
- src/cpp/common/tls_certificate_verifier.cc
- src/cpp/common/tls_credentials_options.cc
- src/cpp/common/validate_service_config.cc
- src/cpp/common/version_cc.cc
- src/cpp/server/async_generic_service.cc
- src/cpp/server/backend_metric_recorder.cc
- src/cpp/server/channel_argument_option.cc
- src/cpp/server/create_default_thread_pool.cc
- src/cpp/server/external_connection_acceptor_impl.cc
- src/cpp/server/health/default_health_check_service.cc
- src/cpp/server/health/health_check_service.cc
- src/cpp/server/health/health_check_service_server_builder_option.cc
- src/cpp/server/insecure_server_credentials.cc
- src/cpp/server/secure_server_credentials.cc
- src/cpp/server/server_builder.cc
- src/cpp/server/server_callback.cc
- src/cpp/server/server_cc.cc
- src/cpp/server/server_context.cc
- src/cpp/server/server_credentials.cc
- src/cpp/server/server_posix.cc
- src/cpp/thread_manager/thread_manager.cc
- src/cpp/util/byte_buffer_cc.cc
- src/cpp/util/status.cc
- src/cpp/util/string_ref.cc
- src/cpp/util/time_cc.cc
- test/core/transport/binder/mock_objects.cc
- test/core/transport/binder/wire_writer_test.cc
deps:
- gtest
- absl/log:absl_check
- absl/log:absl_log
- protobuf
- grpc_test_util
uses_polling: false
- name: work_serializer_test
gtest: true
build: test

2
config.m4 generated

@ -733,7 +733,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/load_balancing/xds/xds_wrr_locality.cc \
src/core/plugin_registry/grpc_plugin_registry.cc \
src/core/plugin_registry/grpc_plugin_registry_extra.cc \
src/core/resolver/binder/binder_resolver.cc \
src/core/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \
src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc \
@ -1606,7 +1605,6 @@ if test "$PHP_GRPC" != "no"; then
PHP_ADD_BUILD_DIR($ext_builddir/src/core/load_balancing/xds)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/plugin_registry)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/resolver)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/resolver/binder)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/resolver/dns)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/resolver/dns/c_ares)
PHP_ADD_BUILD_DIR($ext_builddir/src/core/resolver/dns/event_engine)

2
config.w32 generated

@ -698,7 +698,6 @@ if (PHP_GRPC != "no") {
"src\\core\\load_balancing\\xds\\xds_wrr_locality.cc " +
"src\\core\\plugin_registry\\grpc_plugin_registry.cc " +
"src\\core\\plugin_registry\\grpc_plugin_registry_extra.cc " +
"src\\core\\resolver\\binder\\binder_resolver.cc " +
"src\\core\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " +
"src\\core\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " +
"src\\core\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_windows.cc " +
@ -1748,7 +1747,6 @@ if (PHP_GRPC != "no") {
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\load_balancing\\xds");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\plugin_registry");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\resolver");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\resolver\\binder");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\resolver\\dns");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\resolver\\dns\\c_ares");
FSO.CreateFolder(base_dir+"\\ext\\grpc\\src\\core\\resolver\\dns\\event_engine");

61
gRPC-C++.podspec generated

@ -97,7 +97,6 @@ Pod::Spec.new do |s|
'include/grpcpp/client_context.h',
'include/grpcpp/completion_queue.h',
'include/grpcpp/create_channel.h',
'include/grpcpp/create_channel_binder.h',
'include/grpcpp/create_channel_posix.h',
'include/grpcpp/ext/call_metric_recorder.h',
'include/grpcpp/ext/health_check_service_server_builder_option.h',
@ -185,8 +184,6 @@ Pod::Spec.new do |s|
'include/grpcpp/security/auth_context.h',
'include/grpcpp/security/auth_metadata_processor.h',
'include/grpcpp/security/authorization_policy_provider.h',
'include/grpcpp/security/binder_credentials.h',
'include/grpcpp/security/binder_security_policy.h',
'include/grpcpp/security/credentials.h',
'include/grpcpp/security/server_credentials.h',
'include/grpcpp/security/tls_certificate_provider.h',
@ -313,44 +310,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/rbac/rbac_service_config_parser.h',
'src/core/ext/filters/stateful_session/stateful_session_filter.h',
'src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h',
'src/core/ext/transport/binder/client/binder_connector.cc',
'src/core/ext/transport/binder/client/binder_connector.h',
'src/core/ext/transport/binder/client/channel_create.cc',
'src/core/ext/transport/binder/client/channel_create_impl.cc',
'src/core/ext/transport/binder/client/channel_create_impl.h',
'src/core/ext/transport/binder/client/connection_id_generator.cc',
'src/core/ext/transport/binder/client/connection_id_generator.h',
'src/core/ext/transport/binder/client/endpoint_binder_pool.cc',
'src/core/ext/transport/binder/client/endpoint_binder_pool.h',
'src/core/ext/transport/binder/client/jni_utils.cc',
'src/core/ext/transport/binder/client/jni_utils.h',
'src/core/ext/transport/binder/client/security_policy_setting.cc',
'src/core/ext/transport/binder/client/security_policy_setting.h',
'src/core/ext/transport/binder/security_policy/binder_security_policy.cc',
'src/core/ext/transport/binder/server/binder_server.cc',
'src/core/ext/transport/binder/server/binder_server.h',
'src/core/ext/transport/binder/server/binder_server_credentials.cc',
'src/core/ext/transport/binder/transport/binder_stream.h',
'src/core/ext/transport/binder/transport/binder_transport.cc',
'src/core/ext/transport/binder/transport/binder_transport.h',
'src/core/ext/transport/binder/utils/binder_auto_utils.h',
'src/core/ext/transport/binder/utils/ndk_binder.cc',
'src/core/ext/transport/binder/utils/ndk_binder.h',
'src/core/ext/transport/binder/utils/transport_stream_receiver.h',
'src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc',
'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.cc',
'src/core/ext/transport/binder/wire_format/binder_android.h',
'src/core/ext/transport/binder/wire_format/binder_constants.cc',
'src/core/ext/transport/binder/wire_format/binder_constants.h',
'src/core/ext/transport/binder/wire_format/transaction.cc',
'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.cc',
'src/core/ext/transport/binder/wire_format/wire_reader_impl.h',
'src/core/ext/transport/binder/wire_format/wire_writer.cc',
'src/core/ext/transport/binder/wire_format/wire_writer.h',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',
@ -1640,26 +1599,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/rbac/rbac_service_config_parser.h',
'src/core/ext/filters/stateful_session/stateful_session_filter.h',
'src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h',
'src/core/ext/transport/binder/client/binder_connector.h',
'src/core/ext/transport/binder/client/channel_create_impl.h',
'src/core/ext/transport/binder/client/connection_id_generator.h',
'src/core/ext/transport/binder/client/endpoint_binder_pool.h',
'src/core/ext/transport/binder/client/jni_utils.h',
'src/core/ext/transport/binder/client/security_policy_setting.h',
'src/core/ext/transport/binder/server/binder_server.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/binder_auto_utils.h',
'src/core/ext/transport/binder/utils/ndk_binder.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',
'src/core/ext/transport/chttp2/alpn/alpn.h',
'src/core/ext/transport/chttp2/client/chttp2_connector.h',
'src/core/ext/transport/chttp2/server/chttp2_server.h',

1
gRPC-Core.podspec generated

@ -1825,7 +1825,6 @@ Pod::Spec.new do |s|
'src/core/load_balancing/xds/xds_wrr_locality.cc',
'src/core/plugin_registry/grpc_plugin_registry.cc',
'src/core/plugin_registry/grpc_plugin_registry_extra.cc',
'src/core/resolver/binder/binder_resolver.cc',
'src/core/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/resolver/dns/c_ares/dns_resolver_ares.h',
'src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h',

1
grpc.gemspec generated

@ -1711,7 +1711,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/load_balancing/xds/xds_wrr_locality.cc )
s.files += %w( src/core/plugin_registry/grpc_plugin_registry.cc )
s.files += %w( src/core/plugin_registry/grpc_plugin_registry_extra.cc )
s.files += %w( src/core/resolver/binder/binder_resolver.cc )
s.files += %w( src/core/resolver/dns/c_ares/dns_resolver_ares.cc )
s.files += %w( src/core/resolver/dns/c_ares/dns_resolver_ares.h )
s.files += %w( src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h )

@ -172,7 +172,6 @@
#if __ANDROID_API__ < 21
#error "Requires Android API v21 and above"
#endif
#define GPR_SUPPORT_BINDER_TRANSPORT 1
// TODO(apolcyn): re-evaluate support for c-ares
// on android after upgrading our c-ares dependency.
// See https://github.com/grpc/grpc/issues/18038.

@ -1,125 +0,0 @@
// 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 GRPCPP_CREATE_CHANNEL_BINDER_H
#define GRPCPP_CREATE_CHANNEL_BINDER_H
#include <grpc/support/port_platform.h>
#ifdef GPR_ANDROID
#include <grpcpp/channel.h>
#include <grpcpp/security/binder_security_policy.h>
#include <grpcpp/support/channel_arguments.h>
#include <jni.h>
#include <memory>
#include "absl/strings/string_view.h"
namespace grpc {
namespace experimental {
/// EXPERIMENTAL Create a new \a Channel based on binder transport. The package
/// name and class name will be used identify the specific application component
/// to connect to.
///
/// \param jni_env_void Pointer to a JNIEnv structure
/// \param context The context that we will use to invoke \a bindService See
/// https://developer.android.com/reference/android/content/Context#bindService(android.content.Intent,%20android.content.ServiceConnection,%20int)
/// for detail.
/// \param package_name Package name of the component to be connected to
/// \param class_name Class name of the component to be connected to
/// \param security_policy Used for checking if remote component is allowed to
/// connect
std::shared_ptr<grpc::Channel> CreateBinderChannel(
void* jni_env_void, jobject context, absl::string_view package_name,
absl::string_view class_name,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
/// EXPERIMENTAL Create a new \a Channel based on binder transport. The package
/// name and class name will be used identify the specific application component
/// to connect to.
///
/// \param jni_env_void Pointer to a JNIEnv structure
/// \param context The context that we will use to invoke \a bindService See
/// https://developer.android.com/reference/android/content/Context#bindService(android.content.Intent,%20android.content.ServiceConnection,%20int)
/// for detail.
/// \param package_name Package name of the component to be connected to
/// \param class_name Class name of the component to be connected to
/// \param security_policy Used for checking if remote component is allowed to
/// connect
/// \param args Options for channel creation.
std::shared_ptr<grpc::Channel> CreateCustomBinderChannel(
void* jni_env_void, jobject context, absl::string_view package_name,
absl::string_view class_name,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy,
const ChannelArguments& args);
/// EXPERIMENTAL Create a new \a Channel based on binder transport.
///
/// \param jni_env_void Pointer to a JNIEnv structure
/// \param context The context that we will use to invoke \a bindService See
/// https://developer.android.com/reference/android/content/Context#bindService(android.content.Intent,%20android.content.ServiceConnection,%20int)
/// for detail.
/// \param uri An URI that can be parsed as an `Intent` with
/// https://developer.android.com/reference/android/content/Intent#parseUri(java.lang.String,%20int)
/// \param security_policy Used for checking if remote component is allowed to
/// connect
std::shared_ptr<grpc::Channel> CreateBinderChannel(
void* jni_env_void, jobject context, absl::string_view uri,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
/// EXPERIMENTAL Create a new \a Channel based on binder transport.
///
/// \param jni_env_void Pointer to a JNIEnv structure
/// \param context The context that we will use to invoke \a bindService See
/// https://developer.android.com/reference/android/content/Context#bindService(android.content.Intent,%20android.content.ServiceConnection,%20int)
/// for detail.
/// \param uri An URI that can be parsed as an `Intent` with
/// https://developer.android.com/reference/android/content/Intent#parseUri(java.lang.String,%20int)
/// \param security_policy Used for checking if remote component is allowed to
/// connect
/// \param args Options for channel creation.
std::shared_ptr<grpc::Channel> CreateCustomBinderChannel(
void* jni_env_void, jobject context, absl::string_view uri,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy,
const ChannelArguments& args);
/// EXPERIMENTAL Finds internal binder transport Java code. To create channels
/// in threads created in native code, it is required to call this function
/// once beforehand in a thread that is not created in native code.
/// See
/// https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class
/// for details of this limitation.
/// Returns true when the initialization is successful.
bool InitializeBinderChannelJavaClass(void* jni_env_void);
/// EXPERIMENTAL Alternative version of `InitializeBinderChannelJavaClass(void*
/// jni_env_void)`. This version used a user-specified function to find the
/// required internal Java class. When a class is found, the `class_finder`
/// function should return a local reference to the class (jclass type). The
/// returned jclass will then be used to create global reference for gRPC to use
/// it later. After that, gRPC will DeleteLocalRef the returned local reference.
bool InitializeBinderChannelJavaClass(
void* jni_env_void, std::function<void*(std::string)> class_finder);
} // namespace experimental
} // namespace grpc
#endif
#endif // GRPCPP_CREATE_CHANNEL_BINDER_H

@ -1,43 +0,0 @@
// 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 GRPCPP_SECURITY_BINDER_CREDENTIALS_H
#define GRPCPP_SECURITY_BINDER_CREDENTIALS_H
#include <grpcpp/security/binder_security_policy.h>
#include <grpcpp/security/server_credentials.h>
#include <memory>
namespace grpc {
class ChannelCredentials;
namespace experimental {
/// EXPERIMENTAL Builds Binder ServerCredentials.
///
/// This should be used along with `binder:` URI scheme. The path in the URI can
/// later be used to access the server's endpoint binder.
/// Note that calling \a ServerBuilder::AddListeningPort() with Binder
/// ServerCredentials in a non-supported environment will make the subsequent
/// call to \a ServerBuilder::BuildAndStart() return a null pointer.
std::shared_ptr<grpc::ServerCredentials> BinderServerCredentials(
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_SECURITY_BINDER_CREDENTIALS_H

@ -1,82 +0,0 @@
// 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 GRPCPP_SECURITY_BINDER_SECURITY_POLICY_H
#define GRPCPP_SECURITY_BINDER_SECURITY_POLICY_H
#include <memory>
#ifdef GPR_ANDROID
#include <jni.h>
#endif
namespace grpc {
namespace experimental {
namespace binder {
// EXPERIMENTAL Determinines if a connection is allowed to be
// established on Android. See https://source.android.com/security/app-sandbox
// for more info about UID.
class SecurityPolicy {
public:
virtual ~SecurityPolicy() = default;
// Returns true if the UID is authorized to connect.
// Must return the same value for the same inputs so callers can safely cache
// the result.
virtual bool IsAuthorized(int uid) = 0;
};
// EXPERIMENTAL Allows all connection. Anything on the Android device will be
// able to connect, use with caution!
class UntrustedSecurityPolicy : public SecurityPolicy {
public:
UntrustedSecurityPolicy();
~UntrustedSecurityPolicy() override;
bool IsAuthorized(int uid) override;
};
// EXPERIMENTAL Only allows the connections from processes with the same UID. In
// most cases this means "from the same APK".
class InternalOnlySecurityPolicy : public SecurityPolicy {
public:
InternalOnlySecurityPolicy();
~InternalOnlySecurityPolicy() override;
bool IsAuthorized(int uid) override;
};
#ifdef GPR_ANDROID
// EXPERIMENTAL Only allows the connections from the APK that have the same
// signature.
class SameSignatureSecurityPolicy : public SecurityPolicy {
public:
// `context` is required for getting PackageManager Java class
SameSignatureSecurityPolicy(JavaVM* jvm, jobject context);
~SameSignatureSecurityPolicy() override;
bool IsAuthorized(int uid) override;
private:
JavaVM* jvm_;
jobject context_;
};
#endif
} // namespace binder
} // namespace experimental
} // namespace grpc
#endif // GRPCPP_SECURITY_BINDER_SECURITY_POLICY_H

1
package.xml generated

@ -1693,7 +1693,6 @@
<file baseinstalldir="/" name="src/core/load_balancing/xds/xds_wrr_locality.cc" role="src" />
<file baseinstalldir="/" name="src/core/plugin_registry/grpc_plugin_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/plugin_registry/grpc_plugin_registry_extra.cc" role="src" />
<file baseinstalldir="/" name="src/core/resolver/binder/binder_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/resolver/dns/c_ares/dns_resolver_ares.cc" role="src" />
<file baseinstalldir="/" name="src/core/resolver/dns/c_ares/dns_resolver_ares.h" role="src" />
<file baseinstalldir="/" name="src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h" role="src" />

@ -38,10 +38,7 @@ config_setting(
# the top-level BUILD file that have not yet been moved here. Should go away
# once the transition is complete.
exports_files(
glob(
["**"],
exclude = ["ext/transport/binder/java/**"],
),
glob(["**"]),
visibility = ["//:__subpackages__"],
)
@ -7199,33 +7196,6 @@ grpc_cc_library(
],
)
grpc_cc_library(
name = "grpc_resolver_binder",
srcs = [
"resolver/binder/binder_resolver.cc",
],
external_deps = [
"absl/log:log",
"absl/status",
"absl/status:statusor",
"absl/strings",
],
language = "c++",
deps = [
"channel_args",
"error",
"iomgr_port",
"resolved_address",
"status_helper",
"//:config",
"//:endpoint_addresses",
"//:gpr",
"//:grpc_resolver",
"//:orphanable",
"//:uri",
],
)
grpc_cc_library(
name = "grpc_resolver_xds_attributes",
hdrs = [

@ -1,10 +0,0 @@
# Binder transport for cross process IPC on Android
EXPERIMENTAL. API stability not guaranteed.
This transport implements
[BinderChannel for native cross-process communication on Android](https://github.com/grpc/proposal/blob/master/L73-java-binderchannel.md) and enables C++/Java cross-process communication on Android with gRPC.
Tests: https://github.com/grpc/grpc/tree/master/test/core/transport/binder/
Example apps: https://github.com/grpc/grpc/tree/master/examples/android/binder/java/io/grpc/binder/cpp

@ -1,134 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include "src/core/ext/transport/binder/client/binder_connector.h"
#include "src/core/lib/iomgr/port.h"
#ifdef GRPC_HAVE_UNIX_SOCKET
#ifdef GPR_WINDOWS
// clang-format off
#include <ws2def.h>
#include <afunix.h>
// clang-format on
#else
#include <sys/un.h>
#endif // GPR_WINDOWS
#endif
#include <grpcpp/security/binder_security_policy.h>
#include <functional>
#include <map>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/client_channel/connector.h"
#include "src/core/client_channel/subchannel.h"
#include "src/core/ext/transport/binder/client/endpoint_binder_pool.h"
#include "src/core/ext/transport/binder/client/security_policy_setting.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
namespace {
// TODO(mingcl): Currently this does no error handling and assumes the
// connection always succeeds in reasonable amount of time.
class BinderConnector : public grpc_core::SubchannelConnector {
public:
BinderConnector() {}
~BinderConnector() override {}
void Connect(const Args& args, Result* result,
grpc_closure* notify) override {
#ifdef GRPC_HAVE_UNIX_SOCKET
{
struct sockaddr_un* un =
reinterpret_cast<struct sockaddr_un*>(args.address->addr);
// length of identifier, including null terminator
size_t id_length = args.address->len - sizeof(un->sun_family);
// The c-style string at least will have a null terminator, and the
// connection id itself should not be empty
CHECK_GE(id_length, 2u);
// Make sure there is null terminator at the expected location before
// reading from it
CHECK_EQ(un->sun_path[id_length - 1], '\0');
conn_id_ = un->sun_path;
}
#else
CHECK(0);
#endif
LOG(INFO) << "BinderConnector " << this << " conn_id_ = " << conn_id_;
args_ = args;
CHECK_EQ(notify_, nullptr);
CHECK_NE(notify, nullptr);
notify_ = notify;
result_ = result;
Ref().release(); // Ref held by the following callback
grpc_binder::GetEndpointBinderPool()->GetEndpointBinder(
conn_id_,
std::bind(&BinderConnector::OnConnected, this, std::placeholders::_1));
}
void OnConnected(std::unique_ptr<grpc_binder::Binder> endpoint_binder) {
CHECK(endpoint_binder != nullptr);
grpc_core::Transport* transport = grpc_create_binder_transport_client(
std::move(endpoint_binder),
grpc_binder::GetSecurityPolicySetting()->Get(conn_id_));
CHECK_NE(transport, nullptr);
result_->channel_args = args_.channel_args;
result_->transport = transport;
CHECK_NE(notify_, nullptr);
// ExecCtx is required here for running grpc_closure because this callback
// might be invoked from non-gRPC code
if (grpc_core::ExecCtx::Get() == nullptr) {
grpc_core::ExecCtx exec_ctx;
grpc_core::ExecCtx::Run(DEBUG_LOCATION, notify_, absl::OkStatus());
} else {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, notify_, absl::OkStatus());
}
Unref(); // Was referenced in BinderConnector::Connect
}
void Shutdown(grpc_error_handle /*error*/) override {}
private:
Args args_;
grpc_closure* notify_ = nullptr;
Result* result_ = nullptr;
std::string conn_id_;
};
} // namespace
namespace grpc_core {
RefCountedPtr<Subchannel> BinderClientChannelFactory::CreateSubchannel(
const grpc_resolved_address& address, const ChannelArgs& args) {
LOG(INFO) << "BinderClientChannelFactory creating subchannel " << this;
return Subchannel::Create(
MakeOrphanable<BinderConnector>(), address,
args.Set(GRPC_ARG_DEFAULT_AUTHORITY, "binder.authority"));
}
} // namespace grpc_core
#endif // GRPC_NO_BINDER

@ -1,41 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_BINDER_CONNECTOR_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_BINDER_CONNECTOR_H
#include <grpc/impl/grpc_types.h>
#include <grpc/support/port_platform.h>
#include <grpcpp/channel.h>
#include <grpcpp/support/channel_arguments.h>
#include <memory>
#include <utility>
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "src/core/client_channel/client_channel_factory.h"
#include "src/core/client_channel/client_channel_filter.h"
namespace grpc_core {
class BinderClientChannelFactory : public ClientChannelFactory {
public:
RefCountedPtr<Subchannel> CreateSubchannel(
const grpc_resolved_address& address, const ChannelArgs& args) override;
};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_BINDER_CONNECTOR_H

@ -1,231 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <grpcpp/create_channel_binder.h>
// The interface is only defined if GPR_ANDROID is defined, because some
// arguments requires JNI.
// Furthermore, the interface is non-phony only when
// GPR_SUPPORT_BINDER_TRANSPORT is true because actual implementation of binder
// transport requires newer version of NDK API
#ifdef GPR_ANDROID
#include <grpc/grpc.h>
#include <grpc/grpc_posix.h>
#include "src/core/util/crash.h"
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <grpc/support/port_platform.h>
#include <grpcpp/impl/grpc_library.h>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/strings/substitute.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "src/core/client_channel/client_channel_filter.h"
#include "src/core/ext/transport/binder/client/channel_create_impl.h"
#include "src/core/ext/transport/binder/client/connection_id_generator.h"
#include "src/core/ext/transport/binder/client/endpoint_binder_pool.h"
#include "src/core/ext/transport/binder/client/jni_utils.h"
#include "src/core/ext/transport/binder/client/security_policy_setting.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/binder_android.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/transport/transport.h"
#include "src/cpp/client/create_channel_internal.h"
namespace {
// grpc.io.action.BIND is the standard action name for binding to binder
// transport server.
const char* kStandardActionName = "grpc.io.action.BIND";
} // namespace
namespace grpc {
namespace experimental {
std::shared_ptr<grpc::Channel> CreateBinderChannel(
void* jni_env_void, jobject context, absl::string_view package_name,
absl::string_view class_name,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
return CreateCustomBinderChannel(jni_env_void, context, package_name,
class_name, security_policy,
ChannelArguments());
}
std::shared_ptr<grpc::Channel> CreateCustomBinderChannel(
void* jni_env_void, jobject context, absl::string_view package_name,
absl::string_view class_name,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy,
const ChannelArguments& args) {
return CreateCustomBinderChannel(
jni_env_void, context,
absl::Substitute("android-app://$0#Intent;action=$1;component=$0/$2;end",
package_name, kStandardActionName, class_name),
security_policy, args);
}
std::shared_ptr<grpc::Channel> CreateBinderChannel(
void* jni_env_void, jobject context, absl::string_view uri,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
return CreateCustomBinderChannel(jni_env_void, context, uri, security_policy,
ChannelArguments());
}
std::shared_ptr<grpc::Channel> CreateCustomBinderChannel(
void* jni_env_void, jobject context, absl::string_view uri,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy,
const ChannelArguments& args) {
grpc_init();
CHECK_NE(jni_env_void, nullptr);
CHECK_NE(security_policy, nullptr);
// Generate an unique connection ID that identifies this connection (Useful
// for mapping connection between Java and C++ code).
std::string connection_id =
grpc_binder::GetConnectionIdGenerator()->Generate(uri);
LOG(ERROR) << "connection id is " << connection_id;
// After invoking this Java method, Java code will put endpoint binder into
// `EndpointBinderPool` after the connection succeeds
// TODO(mingcl): Consider if we want to delay the connection establishment
// until SubchannelConnector start establishing connection. For now we don't
// see any benifits doing that.
grpc_binder::TryEstablishConnectionWithUri(static_cast<JNIEnv*>(jni_env_void),
context, uri, connection_id);
grpc_binder::GetSecurityPolicySetting()->Set(connection_id, security_policy);
// Set server URI to a URI that contains connection id. The URI will be used
// by subchannel connector to obtain correct endpoint binder from
// `EndpointBinderPool`.
string server_uri = "binder:" + connection_id;
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
return CreateChannelInternal(
"",
grpc::internal::CreateClientBinderChannelImpl(server_uri, &channel_args),
std::vector<
std::unique_ptr<experimental::ClientInterceptorFactoryInterface>>());
}
bool InitializeBinderChannelJavaClass(void* jni_env_void) {
return grpc_binder::FindNativeConnectionHelper(
static_cast<JNIEnv*>(jni_env_void)) != nullptr;
}
bool InitializeBinderChannelJavaClass(
void* jni_env_void, std::function<void*(std::string)> class_finder) {
return grpc_binder::FindNativeConnectionHelper(
static_cast<JNIEnv*>(jni_env_void), class_finder) != nullptr;
}
} // namespace experimental
} // namespace grpc
#else // !GPR_SUPPORT_BINDER_TRANSPORT
namespace grpc {
namespace experimental {
std::shared_ptr<grpc::Channel> CreateBinderChannel(
void*, jobject, absl::string_view, absl::string_view,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>) {
LOG(ERROR) << "This APK is compiled with Android API level = "
<< __ANDROID_API__
<< ", which is not supported. See port_platform.h for supported "
"versions.";
CHECK(0);
return {};
}
std::shared_ptr<grpc::Channel> CreateCustomBinderChannel(
void*, jobject, absl::string_view, absl::string_view,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>,
const ChannelArguments&) {
LOG(ERROR) << "This APK is compiled with Android API level = "
<< __ANDROID_API__
<< ", which is not supported. See port_platform.h for supported "
"versions.";
CHECK(0);
return {};
}
std::shared_ptr<grpc::Channel> CreateBinderChannel(
void*, jobject, absl::string_view,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>) {
LOG(ERROR) << "This APK is compiled with Android API level = "
<< __ANDROID_API__
<< ", which is not supported. See port_platform.h for supported "
"versions.";
CHECK(0);
return {};
}
std::shared_ptr<grpc::Channel> CreateCustomBinderChannel(
void*, jobject, absl::string_view,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>,
const ChannelArguments&) {
LOG(ERROR) << "This APK is compiled with Android API level = "
<< __ANDROID_API__
<< ", which is not supported. See port_platform.h for supported "
"versions.";
CHECK(0);
return {};
}
bool InitializeBinderChannelJavaClass(void* jni_env_void) {
LOG(ERROR) << "This APK is compiled with Android API level = "
<< __ANDROID_API__
<< ", which is not supported. See port_platform.h for supported "
"versions.";
CHECK(0);
return {};
}
bool InitializeBinderChannelJavaClass(
void* jni_env_void, std::function<void*(std::string)> class_finder) {
LOG(ERROR) << "This APK is compiled with Android API level = "
<< __ANDROID_API__
<< ", which is not supported. See port_platform.h for supported "
"versions.";
CHECK(0);
return {};
}
} // namespace experimental
} // namespace grpc
#endif // GPR_SUPPORT_BINDER_TRANSPORT
#endif // GPR_ANDROID
#endif // GRPC_NO_BINDER

@ -1,93 +0,0 @@
// 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/client/channel_create_impl.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <memory>
#include <utility>
#include "absl/log/check.h"
#include "src/core/ext/transport/binder/client/binder_connector.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/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/channel_create.h"
namespace {
grpc_core::BinderClientChannelFactory* g_factory;
gpr_once g_factory_once = GPR_ONCE_INIT;
void FactoryInit() { g_factory = new grpc_core::BinderClientChannelFactory(); }
} // namespace
namespace grpc {
namespace internal {
grpc_channel* CreateDirectBinderChannelImplForTesting(
std::unique_ptr<grpc_binder::Binder> endpoint_binder,
const grpc_channel_args* args,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
grpc_core::ExecCtx exec_ctx;
grpc_core::Transport* transport = grpc_create_binder_transport_client(
std::move(endpoint_binder), security_policy);
CHECK_NE(transport, nullptr);
auto channel_args = grpc_core::CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(args)
.Set(GRPC_ARG_DEFAULT_AUTHORITY, "binder.authority");
auto channel =
grpc_core::ChannelCreate("binder_target_placeholder", channel_args,
GRPC_CLIENT_DIRECT_CHANNEL, transport);
// TODO(mingcl): Handle error properly
CHECK(channel.ok());
grpc_channel_args_destroy(args);
return channel->release()->c_ptr();
}
grpc_channel* CreateClientBinderChannelImpl(std::string target,
const grpc_channel_args* args) {
grpc_core::ExecCtx exec_ctx;
gpr_once_init(&g_factory_once, FactoryInit);
auto channel_args = grpc_core::CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(args)
.SetObject(g_factory);
auto channel = grpc_core::ChannelCreate(target, channel_args,
GRPC_CLIENT_CHANNEL, nullptr);
if (!channel.ok()) {
return grpc_lame_client_channel_create(
target.c_str(), static_cast<grpc_status_code>(channel.status().code()),
"Failed to create binder channel");
}
return channel->release()->c_ptr();
}
} // namespace internal
} // namespace grpc
#endif

@ -1,42 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CHANNEL_CREATE_IMPL_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CHANNEL_CREATE_IMPL_H
#include <grpc/support/port_platform.h>
#include <grpcpp/security/binder_security_policy.h>
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/lib/channel/channel_args.h"
namespace grpc {
namespace internal {
// Creates a GRPC_CLIENT_DIRECT_CHANNEL channel from endpoint binder
// At this moment this is only used for testing.
grpc_channel* CreateDirectBinderChannelImplForTesting(
std::unique_ptr<grpc_binder::Binder> endpoint_binder,
const grpc_channel_args* args,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
// Creates a GRPC_CLIENT_CHANNEL channel
grpc_channel* CreateClientBinderChannelImpl(std::string target,
const grpc_channel_args* args);
} // namespace internal
} // namespace grpc
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CHANNEL_CREATE_IMPL_H

@ -1,69 +0,0 @@
// 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/client/connection_id_generator.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include "absl/log/check.h"
#include "absl/strings/str_cat.h"
namespace {
// Make sure `s` does not contain characters other than numbers, alphabets,
// period and underscore
std::string Normalize(absl::string_view str_view) {
std::string s = std::string(str_view);
for (size_t i = 0; i < s.length(); i++) {
if (!isalnum(s[i]) && s[i] != '.') {
s[i] = '_';
}
}
return s;
}
// Remove prefix of the string if the string is longer than len
std::string StripToLength(const std::string& s, size_t len) {
if (s.length() > len) {
return s.substr(s.length() - len, len);
}
return s;
}
} // namespace
namespace grpc_binder {
std::string ConnectionIdGenerator::Generate(absl::string_view uri) {
// reserve some room for serial number
const size_t kReserveForNumbers = 15;
std::string s =
StripToLength(Normalize(uri), kPathLengthLimit - kReserveForNumbers);
std::string ret;
{
grpc_core::MutexLock l(&m_);
// Insert a hyphen before serial number
ret = absl::StrCat(s, "-", ++count_);
}
CHECK_LT(ret.length(), kPathLengthLimit);
return ret;
}
ConnectionIdGenerator* GetConnectionIdGenerator() {
static ConnectionIdGenerator* cig = new ConnectionIdGenerator();
return cig;
}
} // namespace grpc_binder
#endif

@ -1,50 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CONNECTION_ID_GENERATOR_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CONNECTION_ID_GENERATOR_H
#include <grpc/support/port_platform.h>
#include <map>
#include "absl/strings/string_view.h"
#include "src/core/util/sync.h"
namespace grpc_binder {
// Generates somewhat human-readable unique identifiers from package name and
// class name. We will generate a Id that only contains unreserved URI
// characters (uppercase and lowercase letters, decimal digits, hyphen, period,
// underscore, and tilde).
class ConnectionIdGenerator {
public:
std::string Generate(absl::string_view uri);
private:
// Our generated Id need to fit in unix socket path length limit. We use 100
// here to be safe.
const size_t kPathLengthLimit = 100;
grpc_core::Mutex m_;
// Every generated identifier will followed by the value of this counter to
// make sure every generated id is unique.
int count_ ABSL_GUARDED_BY(m_);
};
ConnectionIdGenerator* GetConnectionIdGenerator();
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_CONNECTION_ID_GENERATOR_H

@ -1,114 +0,0 @@
// 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/client/endpoint_binder_pool.h"
#include <grpc/support/port_platform.h>
#include "absl/log/check.h"
#include "absl/log/log.h"
#ifndef GRPC_NO_BINDER
#include "src/core/ext/transport/binder/client/jni_utils.h"
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <jni.h>
#include "src/core/ext/transport/binder/wire_format/binder_android.h"
extern "C" {
// Adds endpoint binder to binder pool when Java notify us that the endpoint
// binder is ready. This is called from GrpcBinderConnection.java
JNIEXPORT void JNICALL
Java_io_grpc_binder_cpp_GrpcBinderConnection_notifyConnected__Ljava_lang_String_2Landroid_os_IBinder_2(
JNIEnv* jni_env, jobject, jstring conn_id_jstring, jobject ibinder) {
jboolean isCopy;
const char* conn_id = jni_env->GetStringUTFChars(conn_id_jstring, &isCopy);
LOG(INFO) << __func__ << " invoked with conn_id = " << conn_id;
CHECK_NE(ibinder, nullptr);
grpc_binder::ndk_util::SpAIBinder aibinder =
grpc_binder::FromJavaBinder(jni_env, ibinder);
LOG(INFO) << __func__ << " got aibinder = " << aibinder.get();
auto b = std::make_unique<grpc_binder::BinderAndroid>(aibinder);
CHECK(b != nullptr);
grpc_binder::GetEndpointBinderPool()->AddEndpointBinder(conn_id,
std::move(b));
if (isCopy == JNI_TRUE) {
jni_env->ReleaseStringUTFChars(conn_id_jstring, conn_id);
}
}
}
#endif // GPR_SUPPORT_BINDER_TRANSPORT
namespace grpc_binder {
void EndpointBinderPool::GetEndpointBinder(
std::string conn_id,
std::function<void(std::unique_ptr<grpc_binder::Binder>)> cb) {
LOG(INFO) << "EndpointBinder requested. conn_id = " << conn_id;
std::unique_ptr<grpc_binder::Binder> b;
{
grpc_core::MutexLock l(&m_);
if (binder_map_.count(conn_id)) {
b = std::move(binder_map_[conn_id]);
binder_map_.erase(conn_id);
CHECK(b != nullptr);
} else {
if (pending_requests_.count(conn_id) != 0) {
LOG(ERROR) << "Duplicate GetEndpointBinder requested. conn_id = "
<< conn_id;
return;
}
pending_requests_[conn_id] = std::move(cb);
return;
}
}
CHECK(b != nullptr);
cb(std::move(b));
}
void EndpointBinderPool::AddEndpointBinder(
std::string conn_id, std::unique_ptr<grpc_binder::Binder> b) {
LOG(INFO) << "EndpointBinder added. conn_id = " << conn_id;
CHECK(b != nullptr);
// cb will be set in the following block if there is a pending callback
std::function<void(std::unique_ptr<grpc_binder::Binder>)> cb = nullptr;
{
grpc_core::MutexLock l(&m_);
if (binder_map_.count(conn_id) != 0) {
LOG(ERROR) << "EndpointBinder already in the pool. conn_id = " << conn_id;
return;
}
if (pending_requests_.count(conn_id)) {
cb = std::move(pending_requests_[conn_id]);
pending_requests_.erase(conn_id);
} else {
binder_map_[conn_id] = std::move(b);
b = nullptr;
}
}
if (cb != nullptr) {
cb(std::move(b));
}
}
EndpointBinderPool* GetEndpointBinderPool() {
static EndpointBinderPool* p = new EndpointBinderPool();
return p;
}
} // namespace grpc_binder
#endif

@ -1,64 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_ENDPOINT_BINDER_POOL_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_ENDPOINT_BINDER_POOL_H
#include <grpc/support/port_platform.h>
#include <functional>
#include <string>
#include "absl/container/flat_hash_map.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/util/sync.h"
namespace grpc_binder {
// This class serves as a buffer of endpoint binders between C++ and
// Java. `AddEndpointBinder` will be indirectly invoked by Java code, and
// `GetEndpointBinder` is for C++ code to register callback to get endpoint
// binder when become available. This simplifies JNI related threading issues
// since both side only need to interact with this buffer in non-blocking
// manner and avoids cross-language callbacks.
class EndpointBinderPool {
public:
// Invokes the callback when the binder corresponding to the conn_id become
// available. If the binder is already available, invokes the callback
// immediately.
// Ownership of the endpoint binder will be transferred to the callback
// function and it will be removed from the pool
void GetEndpointBinder(
std::string conn_id,
std::function<void(std::unique_ptr<grpc_binder::Binder>)> cb);
// Add an endpoint binder to the pool
void AddEndpointBinder(std::string conn_id,
std::unique_ptr<grpc_binder::Binder> b);
private:
grpc_core::Mutex m_;
absl::flat_hash_map<std::string, std::unique_ptr<grpc_binder::Binder>>
binder_map_ ABSL_GUARDED_BY(m_);
absl::flat_hash_map<std::string,
std::function<void(std::unique_ptr<grpc_binder::Binder>)>>
pending_requests_ ABSL_GUARDED_BY(m_);
};
// Returns the singleton
EndpointBinderPool* GetEndpointBinderPool();
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_ENDPOINT_BINDER_POOL_H

@ -1,138 +0,0 @@
// 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/client/jni_utils.h"
#include <grpc/support/port_platform.h>
#include "absl/log/check.h"
#include "absl/log/log.h"
#ifndef GRPC_NO_BINDER
#include "src/core/util/crash.h"
#if defined(ANDROID) || defined(__ANDROID__)
namespace grpc_binder {
jclass FindNativeConnectionHelper(JNIEnv* env) {
return FindNativeConnectionHelper(
env, [env](std::string cl) { return env->FindClass(cl.c_str()); });
}
jclass FindNativeConnectionHelper(
JNIEnv* env, std::function<void*(std::string)> class_finder) {
auto do_find = [env, class_finder]() {
jclass cl = static_cast<jclass>(
class_finder("io/grpc/binder/cpp/NativeConnectionHelper"));
if (cl == nullptr) {
return cl;
}
jclass global_cl = static_cast<jclass>(env->NewGlobalRef(cl));
env->DeleteLocalRef(cl);
CHECK_NE(global_cl, nullptr);
return global_cl;
};
static jclass connection_helper_class = do_find();
if (connection_helper_class != nullptr) {
return connection_helper_class;
}
// Some possible reasons:
// * There is no Java class in the call stack and this is not invoked
// from JNI_OnLoad
// * The APK does not correctly depends on the helper class, or the
// class get shrinked
LOG(ERROR)
<< "Cannot find binder transport Java helper class. Did you invoke "
"grpc::experimental::InitializeBinderChannelJavaClass correctly "
"beforehand? Did the APK correctly include the connection helper "
"class (i.e depends on build target "
"src/core/ext/transport/binder/java/io/grpc/binder/"
"cpp:connection_helper) ?";
// TODO(mingcl): Maybe it is worth to try again so the failure can be fixed
// by invoking this function again at a different thread.
return nullptr;
}
void TryEstablishConnection(JNIEnv* env, jobject application,
absl::string_view pkg, absl::string_view cls,
absl::string_view action_name,
absl::string_view conn_id) {
std::string method = "tryEstablishConnection";
std::string type =
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/"
"lang/String;Ljava/lang/String;)V";
jclass cl = FindNativeConnectionHelper(env);
if (cl == nullptr) {
return;
}
jmethodID mid = env->GetStaticMethodID(cl, method.c_str(), type.c_str());
if (mid == nullptr) {
LOG(ERROR) << "No method id " << method;
}
env->CallStaticVoidMethod(cl, mid, application,
env->NewStringUTF(std::string(pkg).c_str()),
env->NewStringUTF(std::string(cls).c_str()),
env->NewStringUTF(std::string(action_name).c_str()),
env->NewStringUTF(std::string(conn_id).c_str()));
}
void TryEstablishConnectionWithUri(JNIEnv* env, jobject application,
absl::string_view uri,
absl::string_view conn_id) {
std::string method = "tryEstablishConnectionWithUri";
std::string type =
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V";
jclass cl = FindNativeConnectionHelper(env);
if (cl == nullptr) {
return;
}
jmethodID mid = env->GetStaticMethodID(cl, method.c_str(), type.c_str());
if (mid == nullptr) {
LOG(ERROR) << "No method id " << method;
}
env->CallStaticVoidMethod(cl, mid, application,
env->NewStringUTF(std::string(uri).c_str()),
env->NewStringUTF(std::string(conn_id).c_str()));
}
bool IsSignatureMatch(JNIEnv* env, jobject context, int uid1, int uid2) {
const std::string method = "isSignatureMatch";
const std::string type = "(Landroid/content/Context;II)Z";
jclass cl = FindNativeConnectionHelper(env);
if (cl == nullptr) {
return false;
}
jmethodID mid = env->GetStaticMethodID(cl, method.c_str(), type.c_str());
if (mid == nullptr) {
LOG(ERROR) << "No method id " << method;
}
jboolean result = env->CallStaticBooleanMethod(cl, mid, context, uid1, uid2);
return result == JNI_TRUE;
}
} // namespace grpc_binder
#endif
#endif

@ -1,57 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_JNI_UTILS_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_JNI_UTILS_H
#if defined(ANDROID) || defined(__ANDROID__)
#include <grpc/support/port_platform.h>
#include <jni.h>
#include <functional>
#include <string>
#include "absl/strings/string_view.h"
namespace grpc_binder {
// Finds NativeConnectionHelper Java class and caches it. This is useful because
// FindClass only works when there is a Java class in the call stack. Typically
// user might want to call this once in a place that is called from Java (ex.
// JNI_OnLoad) so subsequent BinderTransport code can find Java class
jclass FindNativeConnectionHelper(JNIEnv* env);
jclass FindNativeConnectionHelper(
JNIEnv* env, std::function<void*(std::string)> class_finder);
// Calls Java method NativeConnectionHelper.tryEstablishConnection
void TryEstablishConnection(JNIEnv* env, jobject application,
absl::string_view pkg, absl::string_view cls,
absl::string_view action_name,
absl::string_view conn_id);
void TryEstablishConnectionWithUri(JNIEnv* env, jobject application,
absl::string_view uri,
absl::string_view conn_id);
// Calls Java method NativeConnectionHelper.isSignatureMatch.
// Will also return false if failed to invoke Java.
bool IsSignatureMatch(JNIEnv* env, jobject context, int uid1, int uid2);
} // namespace grpc_binder
#endif
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_JNI_UTILS_H

@ -1,47 +0,0 @@
// 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 <grpc/support/port_platform.h>
#include "absl/log/check.h"
#ifndef GRPC_NO_BINDER
#include "src/core/ext/transport/binder/client/security_policy_setting.h"
namespace grpc_binder {
void SecurityPolicySetting::Set(
absl::string_view connection_id,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
grpc_core::MutexLock l(&m_);
CHECK_EQ(security_policy_map_.count(std::string(connection_id)), 0u);
security_policy_map_[std::string(connection_id)] = security_policy;
}
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
SecurityPolicySetting::Get(absl::string_view connection_id) {
grpc_core::MutexLock l(&m_);
CHECK_NE(security_policy_map_.count(std::string(connection_id)), 0u);
return security_policy_map_[std::string(connection_id)];
}
SecurityPolicySetting* GetSecurityPolicySetting() {
static SecurityPolicySetting* s = new SecurityPolicySetting();
return s;
}
} // namespace grpc_binder
#endif

@ -1,49 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_SECURITY_POLICY_SETTING_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_SECURITY_POLICY_SETTING_H
#include <grpc/support/port_platform.h>
#include <grpcpp/security/binder_security_policy.h>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "src/core/util/sync.h"
namespace grpc_binder {
// A singleton class for setting security setting for each connection. This is
// required because we cannot pass security policy shared pointers around using
// gRPC arguments, we can only pass connection_id around as part of URI
class SecurityPolicySetting {
public:
void Set(absl::string_view connection_id,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> Get(
absl::string_view connection_id);
private:
grpc_core::Mutex m_;
absl::flat_hash_map<
std::string, std::shared_ptr<grpc::experimental::binder::SecurityPolicy>>
security_policy_map_ ABSL_GUARDED_BY(m_);
};
SecurityPolicySetting* GetSecurityPolicySetting();
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_CLIENT_SECURITY_POLICY_SETTING_H

@ -1,30 +0,0 @@
# 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.
# copybara: Import internal android_library rule here
licenses(["notice"])
android_library(
name = "connection_helper",
srcs = [
"GrpcBinderConnection.java",
"GrpcCppServerBuilder.java",
"NativeConnectionHelper.java",
],
visibility = ["//visibility:public"],
deps = [
# copybara: Add proguard dependency here
],
)

@ -1,104 +0,0 @@
// 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.
package io.grpc.binder.cpp;
import static android.content.Intent.URI_ANDROID_APP_SCHEME;
import static android.content.Intent.URI_INTENT_SCHEME;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.util.Log;
import java.net.URISyntaxException;
/* Handles the binder connection state with OnDeviceServer server */
public class GrpcBinderConnection implements ServiceConnection {
private static final String logTag = "GrpcBinderConnection";
private Context mContext;
private IBinder mService;
// A string that identifies this service connection
private final String mConnId;
public GrpcBinderConnection(Context context, String connId) {
mContext = context;
mConnId = connId;
}
@Override
public void onNullBinding(ComponentName className) {
// TODO(mingcl): Notify C++ that the connection is never going to happen
Log.e(logTag, "Service returned null IBinder. mConnId = " + mConnId);
}
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.e(logTag, "Service has connected. mConnId = " + mConnId);
if (service == null) {
// This should not happen since onNullBinding should be invoked instead
throw new IllegalArgumentException("service was null");
}
synchronized (this) {
mService = service;
}
notifyConnected(mConnId, mService);
}
@Override
public void onServiceDisconnected(ComponentName className) {
Log.e(logTag, "Service has disconnected. mConnId = " + mConnId);
}
public void tryConnect(String pkg, String cls, String action_name) {
Intent intent = new Intent(action_name);
ComponentName compName = new ComponentName(pkg, cls);
intent.setComponent(compName);
tryConnect(intent);
}
@TargetApi(22)
public void tryConnect(String uri) {
// Try connect with an URI that can be parsed as intent.
try {
tryConnect(Intent.parseUri(uri, URI_ANDROID_APP_SCHEME | URI_INTENT_SCHEME));
} catch (URISyntaxException e) {
Log.e(logTag, "Unable to parse the Uri: " + uri);
}
}
private void tryConnect(Intent intent) {
synchronized (this) {
// Will return true if the system is in the process of bringing up a service that your client
// has permission to bind to; false if the system couldn't find the service or if your client
// doesn't have permission to bind to it
boolean result = mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
if (result) {
Log.e(logTag, "bindService returns ok");
} else {
Log.e(
logTag,
"bindService failed. Maybe the system couldn't find the service or the"
+ " client doesn't have permission to bind to it.");
}
}
}
// Calls a function defined in endpoint_binder_pool.cc
private static native void notifyConnected(String connId, IBinder service);
}

@ -1,40 +0,0 @@
// 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.
package io.grpc.binder.cpp;
import android.os.IBinder;
import android.util.Log;
/* EXPERIMENTAL. Provides a interface to get endpoint binder from C++ */
public class GrpcCppServerBuilder {
private static final String logTag = "GrpcCppServerBuilder";
public static IBinder GetEndpointBinder(String uri) {
String scheme = "binder:";
if (uri.startsWith(scheme)) {
String path = uri.substring(scheme.length());
// TODO(mingcl): Consider if we would like to make sure the path only contain valid
// characters here
IBinder ibinder = GetEndpointBinderInternal(path);
Log.e(logTag, "Returning binder=" + ibinder + " for URI=" + uri);
return ibinder;
} else {
Log.e(logTag, "URI " + uri + " does not start with 'binder:'");
return null;
}
}
private static native IBinder GetEndpointBinderInternal(String conn_id);
}

@ -1,71 +0,0 @@
// 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.
package io.grpc.binder.cpp;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Parcel;
import android.util.Log;
// copybara: Import proguard UsedByNative annotation here
import java.util.HashMap;
import java.util.Map;
/**
* This class will be invoked by gRPC binder transport internal implementation (from
* src/core/ext/transport/binder/client/jni_utils.cc) to perform operations that are only possible
* in Java
*/
// copybara: Add @UsedByNative("jni_utils.cc")
final class NativeConnectionHelper {
// Maps connection id to GrpcBinderConnection instances
static Map<String, GrpcBinderConnection> connectionIdToGrpcBinderConnectionMap = new HashMap<>();
// copybara: Add @UsedByNative("jni_utils.cc")
static void tryEstablishConnection(
Context context, String pkg, String cls, String actionName, String connId) {
// TODO(mingcl): Assert that connId is unique
connectionIdToGrpcBinderConnectionMap.put(connId, new GrpcBinderConnection(context, connId));
connectionIdToGrpcBinderConnectionMap.get(connId).tryConnect(pkg, cls, actionName);
}
// copybara: Add @UsedByNative("jni_utils.cc")
static void tryEstablishConnectionWithUri(Context context, String uri, String connId) {
// TODO(mingcl): Assert that connId is unique
connectionIdToGrpcBinderConnectionMap.put(connId, new GrpcBinderConnection(context, connId));
connectionIdToGrpcBinderConnectionMap.get(connId).tryConnect(uri);
}
// Returns true if the packages signature of the 2 UIDs match.
// `context` is used to get PackageManager.
// Suppress unnecessary internal warnings related to checkSignatures compatibility issue.
// BinderTransport code is only used on newer Android platform versions so this is fine.
@SuppressWarnings("CheckSignatures")
// copybara: Add @UsedByNative("jni_utils.cc")
static boolean isSignatureMatch(Context context, int uid1, int uid2) {
int result = context.getPackageManager().checkSignatures(uid1, uid2);
if (result == PackageManager.SIGNATURE_MATCH) {
return true;
}
Log.e(
"NativeConnectionHelper",
"Signatures does not match. checkSignature return value = " + result);
return false;
}
// copybara: Add @UsedByNative("jni_utils.cc")
static Parcel getEmptyParcel() {
return Parcel.obtain();
}
}

@ -1,106 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <grpcpp/security/binder_security_policy.h>
#ifdef GPR_ANDROID
#include <jni.h>
#include <unistd.h>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/ext/transport/binder/client/jni_utils.h"
#include "src/core/util/crash.h"
#endif
namespace grpc {
namespace experimental {
namespace binder {
UntrustedSecurityPolicy::UntrustedSecurityPolicy() = default;
UntrustedSecurityPolicy::~UntrustedSecurityPolicy() = default;
bool UntrustedSecurityPolicy::IsAuthorized(int) { return true; };
InternalOnlySecurityPolicy::InternalOnlySecurityPolicy() = default;
InternalOnlySecurityPolicy::~InternalOnlySecurityPolicy() = default;
#ifdef GPR_ANDROID
bool InternalOnlySecurityPolicy::IsAuthorized(int uid) {
return static_cast<uid_t>(uid) == getuid();
}
#else
bool InternalOnlySecurityPolicy::IsAuthorized(int) { return false; }
#endif
#ifdef GPR_ANDROID
namespace {
JNIEnv* GetEnv(JavaVM* vm) {
if (vm == nullptr) return nullptr;
JNIEnv* result = nullptr;
jint attach = vm->AttachCurrentThread(&result, nullptr);
CHECK(JNI_OK == attach);
CHECK_NE(result, nullptr);
return result;
}
} // namespace
SameSignatureSecurityPolicy::SameSignatureSecurityPolicy(JavaVM* jvm,
jobject context)
: jvm_(jvm) {
CHECK_NE(jvm, nullptr);
CHECK_NE(context, nullptr);
JNIEnv* env = GetEnv(jvm_);
// Make sure the context is still valid when IsAuthorized() is called
context_ = env->NewGlobalRef(context);
CHECK_NE(context_, nullptr);
}
SameSignatureSecurityPolicy::~SameSignatureSecurityPolicy() {
JNIEnv* env = GetEnv(jvm_);
env->DeleteLocalRef(context_);
}
bool SameSignatureSecurityPolicy::IsAuthorized(int uid) {
JNIEnv* env = GetEnv(jvm_);
bool result = grpc_binder::IsSignatureMatch(env, context_, getuid(), uid);
if (result) {
LOG(INFO) << "uid " << getuid() << " and uid " << uid
<< " passed SameSignature check";
} else {
LOG(ERROR) << "uid " << getuid() << " and uid " << uid
<< " failed SameSignature check";
}
return result;
}
#endif
} // namespace binder
} // namespace experimental
} // namespace grpc
#endif

@ -1,40 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_SECURITY_POLICY_SECURITY_POLICY_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SECURITY_POLICY_SECURITY_POLICY_H
#include <grpc/support/port_platform.h>
namespace grpc {
namespace experimental {
namespace binder {
// This interface is for determining if a connection is allowed to be
// established on Android. See https://source.android.com/security/app-sandbox
// for more info about UID.
class SecurityPolicy {
public:
virtual ~SecurityPolicy() = default;
// Returns true if the UID is authorized to connect.
// Must return the same value for the same inputs so callers can safely cache
// the result.
virtual bool IsAuthorized(int uid) = 0;
};
} // namespace binder
} // namespace experimental
} // namespace grpc
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SECURITY_POLICY_SECURITY_POLICY_H

@ -1,249 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <grpc/grpc.h>
#include <memory>
#include <string>
#include <utility>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/ext/transport/binder/utils/ndk_binder.h"
#include "src/core/ext/transport/binder/wire_format/binder_android.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/server/server.h"
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <jni.h>
extern "C" {
// This will be invoked from
// src/core/ext/transport/binder/java/io/grpc/binder/cpp/GrpcCppServerBuilder.java
JNIEXPORT jobject JNICALL
Java_io_grpc_binder_cpp_GrpcCppServerBuilder_GetEndpointBinderInternal__Ljava_lang_String_2(
JNIEnv* jni_env, jobject, jstring conn_id_jstring) {
grpc_binder::ndk_util::AIBinder* ai_binder = nullptr;
{
// This block is the scope of conn_id c-string
jboolean isCopy;
const char* conn_id = jni_env->GetStringUTFChars(conn_id_jstring, &isCopy);
ai_binder = static_cast<grpc_binder::ndk_util::AIBinder*>(
grpc_get_endpoint_binder(std::string(conn_id)));
if (ai_binder == nullptr) {
LOG(ERROR) << "Cannot find endpoint binder with connection id = "
<< conn_id;
}
if (isCopy == JNI_TRUE) {
jni_env->ReleaseStringUTFChars(conn_id_jstring, conn_id);
}
}
if (ai_binder == nullptr) {
return nullptr;
}
return grpc_binder::ndk_util::AIBinder_toJavaBinder(jni_env, ai_binder);
}
}
#endif
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
static absl::flat_hash_map<std::string, void*>* g_endpoint_binder_pool =
nullptr;
namespace {
grpc_core::Mutex* GetBinderPoolMutex() {
static grpc_core::Mutex* mu = new grpc_core::Mutex();
return mu;
}
} // namespace
void grpc_add_endpoint_binder(const std::string& service,
void* endpoint_binder) {
grpc_core::MutexLock lock(GetBinderPoolMutex());
if (g_endpoint_binder_pool == nullptr) {
g_endpoint_binder_pool = new absl::flat_hash_map<std::string, void*>();
}
(*g_endpoint_binder_pool)[service] = endpoint_binder;
}
void grpc_remove_endpoint_binder(const std::string& service) {
grpc_core::MutexLock lock(GetBinderPoolMutex());
if (g_endpoint_binder_pool == nullptr) {
return;
}
g_endpoint_binder_pool->erase(service);
}
void* grpc_get_endpoint_binder(const std::string& service) {
grpc_core::MutexLock lock(GetBinderPoolMutex());
if (g_endpoint_binder_pool == nullptr) {
return nullptr;
}
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,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy)
: server_(server),
addr_(std::move(addr)),
factory_(std::move(factory)),
security_policy_(security_policy) {}
void Start(Server* /*server*/,
const std::vector<grpc_pollset*>* /*pollsets*/) override {
tx_receiver_ = factory_(
[this](transaction_code_t code, grpc_binder::ReadableParcel* parcel,
int uid) { return OnSetupTransport(code, parcel, uid); });
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 { Unref(); }
~BinderServerListener() override {
ExecCtx::Get()->Flush();
if (on_destroy_done_) {
ExecCtx::Run(DEBUG_LOCATION, on_destroy_done_, absl::OkStatus());
ExecCtx::Get()->Flush();
}
grpc_remove_endpoint_binder(addr_);
}
private:
absl::Status OnSetupTransport(transaction_code_t code,
grpc_binder::ReadableParcel* parcel, int uid) {
ExecCtx exec_ctx;
if (static_cast<grpc_binder::BinderTransportTxCode>(code) !=
grpc_binder::BinderTransportTxCode::SETUP_TRANSPORT) {
return absl::InvalidArgumentError("Not a SETUP_TRANSPORT request");
}
LOG(INFO) << "BinderServerListener calling uid = " << uid;
if (!security_policy_->IsAuthorized(uid)) {
// TODO(mingcl): For now we just ignore this unauthorized
// SETUP_TRANSPORT transaction and ghost the client. Check if we should
// send back a SHUTDOWN_TRANSPORT in this case.
return absl::PermissionDeniedError(
"UID " + std::to_string(uid) +
" is not allowed to connect to this "
"server according to security policy.");
}
int version;
absl::Status status = parcel->ReadInt32(&version);
if (!status.ok()) {
return status;
}
LOG(INFO) << "BinderTransport client protocol version = " << version;
// TODO(mingcl): Make sure we only give client a version that is not newer
// than the version they specify. For now, we always tell client that we
// only support version=1.
std::unique_ptr<grpc_binder::Binder> 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().
Transport* server_transport = grpc_create_binder_transport_server(
std::move(client_binder), security_policy_);
CHECK(server_transport);
grpc_error_handle error = server_->SetupTransport(
server_transport, nullptr, server_->channel_args(), nullptr);
return grpc_error_to_absl_status(error);
}
Server* server_;
grpc_closure* on_destroy_done_ = nullptr;
std::string addr_;
BinderTxReceiverFactory factory_;
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy_;
void* endpoint_binder_ = nullptr;
std::unique_ptr<grpc_binder::TransactionReceiver> tx_receiver_;
};
bool AddBinderPort(const std::string& addr, grpc_server* server,
BinderTxReceiverFactory factory,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
// TODO(mingcl): Check if the addr is valid here after binder address resolver
// related code are merged.
const std::string kBinderUriScheme = "binder:";
if (addr.compare(0, kBinderUriScheme.size(), kBinderUriScheme) != 0) {
return false;
}
std::string conn_id = addr.substr(kBinderUriScheme.size());
Server* core_server = Server::FromC(server);
core_server->AddListener(MakeOrphanable<BinderServerListener>(
core_server, conn_id, std::move(factory), security_policy));
return true;
}
} // namespace grpc_core
#endif

@ -1,65 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_H
#include <grpc/support/port_platform.h>
#include <grpcpp/security/binder_security_policy.h>
#include <string>
#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/transport/error_utils.h"
#include "src/core/server/server.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
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<std::unique_ptr<grpc_binder::TransactionReceiver>(
grpc_binder::TransactionReceiver::OnTransactCb)>;
bool AddBinderPort(const std::string& addr, grpc_server* server,
BinderTxReceiverFactory factory,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
} // namespace grpc_core
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_SERVER_BINDER_SERVER_H

@ -1,71 +0,0 @@
// 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 <grpc/support/port_platform.h>
#include "absl/log/check.h"
#ifndef GRPC_NO_BINDER
#include <grpcpp/security/binder_security_policy.h>
#include <grpcpp/security/server_credentials.h>
#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:
explicit BinderServerCredentialsImpl(
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy)
: ServerCredentials(nullptr), security_policy_(security_policy) {}
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
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 std::make_unique<grpc_binder::TransactionReceiverAndroid>(
nullptr, std::move(transact_cb));
},
security_policy_);
}
#else
int AddPortToServer(const std::string& /*addr*/,
grpc_server* /*server*/) override {
return 0;
}
#endif // GPR_SUPPORT_BINDER_TRANSPORT
private:
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy_;
};
} // namespace
std::shared_ptr<ServerCredentials> BinderServerCredentials(
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
CHECK_NE(security_policy, nullptr);
return std::shared_ptr<ServerCredentials>(
new BinderServerCredentialsImpl(security_policy));
}
} // namespace experimental
} // namespace grpc
#endif

@ -1,117 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_STREAM_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_STREAM_H
#include <grpc/support/port_platform.h>
#include "src/core/ext/transport/binder/transport/binder_transport.h"
struct RecvInitialMetadataArgs {
grpc_binder_stream* stream;
grpc_binder_transport* transport;
int tx_code;
absl::StatusOr<grpc_binder::Metadata> initial_metadata;
};
struct RecvMessageArgs {
grpc_binder_stream* stream;
grpc_binder_transport* transport;
int tx_code;
absl::StatusOr<std::string> message;
};
struct RecvTrailingMetadataArgs {
grpc_binder_stream* stream;
grpc_binder_transport* transport;
int tx_code;
absl::StatusOr<grpc_binder::Metadata> trailing_metadata;
int status;
};
struct RegisterStreamArgs {
grpc_binder_stream* stream;
grpc_binder_transport* transport;
};
// TODO(mingcl): Figure out if we want to use class instead of struct here
struct grpc_binder_stream {
// server_data will be null for client, and for server it will be whatever
// passed in to the accept_stream_fn callback by client.
grpc_binder_stream(grpc_binder_transport* t, grpc_stream_refcount* refcount,
const void* /*server_data*/, grpc_core::Arena* arena,
int tx_code, bool is_client)
: t(t),
refcount(refcount),
arena(arena),
tx_code(tx_code),
is_client(is_client),
is_closed(false) {
recv_initial_metadata_args.stream = this;
recv_initial_metadata_args.transport = t;
recv_message_args.stream = this;
recv_message_args.transport = t;
recv_trailing_metadata_args.stream = this;
recv_trailing_metadata_args.transport = t;
}
~grpc_binder_stream() {
if (destroy_stream_then_closure != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, destroy_stream_then_closure,
absl::OkStatus());
}
}
int GetTxCode() const { return tx_code; }
grpc_binder_transport* t;
grpc_stream_refcount* refcount;
grpc_core::Arena* arena;
int tx_code;
const bool is_client;
bool is_closed;
grpc_closure* destroy_stream_then_closure = nullptr;
grpc_closure destroy_stream;
// The reason why this stream is cancelled and closed.
grpc_error_handle cancel_self_error;
grpc_closure recv_initial_metadata_closure;
RecvInitialMetadataArgs recv_initial_metadata_args;
grpc_closure recv_message_closure;
RecvMessageArgs recv_message_args;
grpc_closure recv_trailing_metadata_closure;
RecvTrailingMetadataArgs recv_trailing_metadata_args;
grpc_closure register_stream_closure;
RegisterStreamArgs register_stream_args;
// We store these fields passed from op batch, in order to access them through
// grpc_binder_stream
grpc_metadata_batch* recv_initial_metadata;
grpc_closure* recv_initial_metadata_ready = nullptr;
bool* trailing_metadata_available = nullptr;
absl::optional<grpc_core::SliceBuffer>* recv_message;
grpc_closure* recv_message_ready = nullptr;
bool* call_failed_before_recv_message = nullptr;
grpc_metadata_batch* recv_trailing_metadata;
grpc_closure* recv_trailing_metadata_finished = nullptr;
bool trailing_metadata_sent = false;
bool need_to_call_trailing_metadata_callback = false;
};
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_STREAM_H

@ -1,758 +0,0 @@
// 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/transport/binder_transport.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"
#include "src/core/ext/transport/binder/transport/binder_stream.h"
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/ext/transport/binder/utils/transport_stream_receiver_impl.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader_impl.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/util/crash.h"
#ifndef NDEBUG
static void grpc_binder_stream_ref(grpc_binder_stream* s, const char* reason) {
grpc_stream_ref(s->refcount, reason);
}
static void grpc_binder_stream_unref(grpc_binder_stream* s,
const char* reason) {
grpc_stream_unref(s->refcount, reason);
}
static void grpc_binder_ref_transport(grpc_binder_transport* t,
const char* reason, const char* file,
int line) {
t->refs.Ref(grpc_core::DebugLocation(file, line), reason);
}
static void grpc_binder_unref_transport(grpc_binder_transport* t,
const char* reason, const char* file,
int line) {
if (t->refs.Unref(grpc_core::DebugLocation(file, line), reason)) {
delete t;
}
}
#else
static void grpc_binder_stream_ref(grpc_binder_stream* s) {
grpc_stream_ref(s->refcount);
}
static void grpc_binder_stream_unref(grpc_binder_stream* s) {
grpc_stream_unref(s->refcount);
}
static void grpc_binder_ref_transport(grpc_binder_transport* t) {
t->refs.Ref();
}
static void grpc_binder_unref_transport(grpc_binder_transport* t) {
if (t->refs.Unref()) {
delete t;
}
}
#endif
#ifndef NDEBUG
#define GRPC_BINDER_STREAM_REF(stream, reason) \
grpc_binder_stream_ref(stream, reason)
#define GRPC_BINDER_STREAM_UNREF(stream, reason) \
grpc_binder_stream_unref(stream, reason)
#define GRPC_BINDER_REF_TRANSPORT(t, r) \
grpc_binder_ref_transport(t, r, __FILE__, __LINE__)
#define GRPC_BINDER_UNREF_TRANSPORT(t, r) \
grpc_binder_unref_transport(t, r, __FILE__, __LINE__)
#else
#define GRPC_BINDER_STREAM_REF(stream, reason) grpc_binder_stream_ref(stream)
#define GRPC_BINDER_STREAM_UNREF(stream, reason) \
grpc_binder_stream_unref(stream)
#define GRPC_BINDER_REF_TRANSPORT(t, r) grpc_binder_ref_transport(t)
#define GRPC_BINDER_UNREF_TRANSPORT(t, r) grpc_binder_unref_transport(t)
#endif
static void register_stream_locked(void* arg, grpc_error_handle /*error*/) {
RegisterStreamArgs* args = static_cast<RegisterStreamArgs*>(arg);
args->transport->registered_stream[args->stream->GetTxCode()] = args->stream;
}
void grpc_binder_transport::InitStream(grpc_stream* gs,
grpc_stream_refcount* refcount,
const void* server_data,
grpc_core::Arena* arena) {
LOG(INFO) << __func__ << " = " << this << " " << gs << " " << refcount << " "
<< server_data << " " << arena;
// Note that this function is not locked and may be invoked concurrently
new (gs) grpc_binder_stream(this, refcount, server_data, arena,
NewStreamTxCode(), is_client);
// `grpc_binder_transport::registered_stream` should only be updated in
// combiner
grpc_binder_stream* stream = reinterpret_cast<grpc_binder_stream*>(gs);
stream->register_stream_args.stream = stream;
stream->register_stream_args.transport = this;
grpc_core::ExecCtx exec_ctx;
combiner->Run(GRPC_CLOSURE_INIT(&stream->register_stream_closure,
register_stream_locked,
&stream->register_stream_args, nullptr),
absl::OkStatus());
}
static void AssignMetadata(grpc_metadata_batch* mb,
const grpc_binder::Metadata& md) {
mb->Clear();
for (auto& p : md) {
mb->Append(p.first, grpc_core::Slice::FromCopiedString(p.second),
[&](absl::string_view error, const grpc_core::Slice&) {
VLOG(2) << "Failed to parse metadata: "
<< "key=" << p.first << " error=" << error;
});
}
}
static void cancel_stream_locked(grpc_binder_transport* transport,
grpc_binder_stream* stream,
grpc_error_handle error) {
LOG(INFO) << "cancel_stream_locked";
if (!stream->is_closed) {
CHECK(stream->cancel_self_error.ok());
stream->is_closed = true;
stream->cancel_self_error = error;
transport->transport_stream_receiver->CancelStream(stream->tx_code);
transport->registered_stream.erase(stream->tx_code);
if (stream->recv_initial_metadata_ready != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION,
stream->recv_initial_metadata_ready, error);
stream->recv_initial_metadata_ready = nullptr;
stream->recv_initial_metadata = nullptr;
stream->trailing_metadata_available = nullptr;
}
if (stream->recv_message_ready != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, stream->recv_message_ready,
error);
stream->recv_message_ready = nullptr;
stream->recv_message->reset();
stream->recv_message = nullptr;
stream->call_failed_before_recv_message = nullptr;
}
if (stream->recv_trailing_metadata_finished != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION,
stream->recv_trailing_metadata_finished, error);
stream->recv_trailing_metadata_finished = nullptr;
stream->recv_trailing_metadata = nullptr;
}
}
}
static bool ContainsAuthorityAndPath(const grpc_binder::Metadata& metadata) {
bool has_authority = false;
bool has_path = false;
for (const auto& kv : metadata) {
if (kv.first == ":authority") {
has_authority = true;
}
if (kv.first == ":path") {
has_path = true;
}
}
return has_authority && has_path;
}
static void recv_initial_metadata_locked(void* arg,
grpc_error_handle /*error*/) {
RecvInitialMetadataArgs* args = static_cast<RecvInitialMetadataArgs*>(arg);
grpc_binder_stream* stream = args->stream;
LOG(INFO) << "recv_initial_metadata_locked is_client = " << stream->is_client
<< " is_closed = " << stream->is_closed;
if (!stream->is_closed) {
grpc_error_handle error = [&] {
CHECK(stream->recv_initial_metadata);
CHECK(stream->recv_initial_metadata_ready);
if (!args->initial_metadata.ok()) {
LOG(ERROR) << "Failed to parse initial metadata";
return absl_status_to_grpc_error(args->initial_metadata.status());
}
if (!stream->is_client) {
// For server, we expect :authority and :path in initial metadata.
if (!ContainsAuthorityAndPath(*args->initial_metadata)) {
return GRPC_ERROR_CREATE(
"Missing :authority or :path in initial metadata");
}
}
AssignMetadata(stream->recv_initial_metadata, *args->initial_metadata);
return absl::OkStatus();
}();
if (stream->t->registered_method_matcher_cb != nullptr) {
stream->t->registered_method_matcher_cb(
stream->t->accept_stream_user_data, stream->recv_initial_metadata);
}
grpc_closure* cb = stream->recv_initial_metadata_ready;
stream->recv_initial_metadata_ready = nullptr;
stream->recv_initial_metadata = nullptr;
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
}
GRPC_BINDER_STREAM_UNREF(stream, "recv_initial_metadata");
}
static void recv_message_locked(void* arg, grpc_error_handle /*error*/) {
RecvMessageArgs* args = static_cast<RecvMessageArgs*>(arg);
grpc_binder_stream* stream = args->stream;
LOG(INFO) << "recv_message_locked is_client = " << stream->is_client
<< " is_closed = " << stream->is_closed;
if (!stream->is_closed) {
grpc_error_handle error = [&] {
CHECK(stream->recv_message);
CHECK(stream->recv_message_ready);
if (!args->message.ok()) {
LOG(ERROR) << "Failed to receive message";
if (args->message.status().message() ==
grpc_binder::TransportStreamReceiver::
kGrpcBinderTransportCancelledGracefully) {
LOG(ERROR) << "message cancelled gracefully";
// Cancelled because we've already received trailing metadata.
// It's not an error in this case.
return absl::OkStatus();
} else {
return absl_status_to_grpc_error(args->message.status());
}
}
grpc_core::SliceBuffer buf;
buf.Append(grpc_core::Slice(grpc_slice_from_cpp_string(*args->message)));
*stream->recv_message = std::move(buf);
return absl::OkStatus();
}();
if (!error.ok() && stream->call_failed_before_recv_message != nullptr) {
*stream->call_failed_before_recv_message = true;
}
grpc_closure* cb = stream->recv_message_ready;
stream->recv_message_ready = nullptr;
stream->recv_message = nullptr;
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
}
GRPC_BINDER_STREAM_UNREF(stream, "recv_message");
}
static void recv_trailing_metadata_locked(void* arg,
grpc_error_handle /*error*/) {
RecvTrailingMetadataArgs* args = static_cast<RecvTrailingMetadataArgs*>(arg);
grpc_binder_stream* stream = args->stream;
LOG(INFO) << "recv_trailing_metadata_locked is_client = " << stream->is_client
<< " is_closed = " << stream->is_closed;
if (!stream->is_closed) {
grpc_error_handle error = [&] {
CHECK(stream->recv_trailing_metadata);
CHECK(stream->recv_trailing_metadata_finished);
if (!args->trailing_metadata.ok()) {
LOG(ERROR) << "Failed to receive trailing metadata";
return absl_status_to_grpc_error(args->trailing_metadata.status());
}
if (!stream->is_client) {
// Client will not send non-empty trailing metadata.
if (!args->trailing_metadata.value().empty()) {
LOG(ERROR) << "Server receives non-empty trailing metadata.";
return absl::CancelledError();
}
} else {
AssignMetadata(stream->recv_trailing_metadata,
*args->trailing_metadata);
// Append status to metadata
// TODO(b/192208695): See if we can avoid to manually put status
// code into the header
LOG(INFO) << "status = " << args->status;
stream->recv_trailing_metadata->Set(
grpc_core::GrpcStatusMetadata(),
static_cast<grpc_status_code>(args->status));
}
return absl::OkStatus();
}();
if (stream->is_client || stream->trailing_metadata_sent) {
grpc_closure* cb = stream->recv_trailing_metadata_finished;
stream->recv_trailing_metadata_finished = nullptr;
stream->recv_trailing_metadata = nullptr;
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, error);
} else {
// According to transport explaineer - "Server extra: This op shouldn't
// actually be considered complete until the server has also sent trailing
// metadata to provide the other side with final status"
//
// We haven't sent trailing metadata yet, so we have to delay completing
// the recv_trailing_metadata callback.
stream->need_to_call_trailing_metadata_callback = true;
}
}
GRPC_BINDER_STREAM_UNREF(stream, "recv_trailing_metadata");
}
namespace grpc_binder {
namespace {
class MetadataEncoder {
public:
MetadataEncoder(bool is_client, Transaction* tx, Metadata* init_md)
: is_client_(is_client), tx_(tx), init_md_(init_md) {}
void Encode(const grpc_core::Slice& key_slice,
const grpc_core::Slice& value_slice) {
absl::string_view key = key_slice.as_string_view();
absl::string_view value = value_slice.as_string_view();
init_md_->emplace_back(std::string(key), std::string(value));
}
void Encode(grpc_core::HttpPathMetadata, const grpc_core::Slice& value) {
// TODO(b/192208403): Figure out if it is correct to simply drop '/'
// prefix and treat it as rpc method name
CHECK(value[0] == '/');
std::string path = std::string(value.as_string_view().substr(1));
// Only client send method ref.
CHECK(is_client_);
tx_->SetMethodRef(path);
}
void Encode(grpc_core::GrpcStatusMetadata, grpc_status_code status) {
LOG(INFO) << "send trailing metadata status = " << status;
tx_->SetStatus(status);
}
template <typename Trait>
void Encode(Trait, const typename Trait::ValueType& value) {
init_md_->emplace_back(std::string(Trait::key()),
std::string(Trait::Encode(value).as_string_view()));
}
private:
const bool is_client_;
Transaction* const tx_;
Metadata* const init_md_;
};
} // namespace
} // namespace grpc_binder
static void accept_stream_locked(void* gt, grpc_error_handle /*error*/) {
grpc_binder_transport* transport = static_cast<grpc_binder_transport*>(gt);
if (transport->accept_stream_fn) {
LOG(INFO) << "Accepting a stream";
// must pass in a non-null value.
(*transport->accept_stream_fn)(transport->accept_stream_user_data,
transport, transport);
} else {
++transport->accept_stream_fn_called_count_;
LOG(INFO) << "accept_stream_fn not set, current count = "
<< transport->accept_stream_fn_called_count_;
}
}
static void perform_stream_op_locked(void* stream_op,
grpc_error_handle /*error*/) {
grpc_transport_stream_op_batch* op =
static_cast<grpc_transport_stream_op_batch*>(stream_op);
grpc_binder_stream* stream =
static_cast<grpc_binder_stream*>(op->handler_private.extra_arg);
grpc_binder_transport* transport = stream->t;
if (op->cancel_stream) {
// TODO(waynetu): Is this true?
CHECK(!op->send_initial_metadata && !op->send_message &&
!op->send_trailing_metadata && !op->recv_initial_metadata &&
!op->recv_message && !op->recv_trailing_metadata);
LOG(INFO) << "cancel_stream is_client = " << stream->is_client;
if (!stream->is_client) {
// Send trailing metadata to inform the other end about the cancellation,
// regardless if we'd already done that or not.
auto cancel_tx = std::make_unique<grpc_binder::Transaction>(
stream->GetTxCode(), transport->is_client);
cancel_tx->SetSuffix(grpc_binder::Metadata{});
cancel_tx->SetStatus(1);
(void)transport->wire_writer->RpcCall(std::move(cancel_tx));
}
cancel_stream_locked(transport, stream,
op->payload->cancel_stream.cancel_error);
if (op->on_complete != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_complete,
absl::OkStatus());
}
GRPC_BINDER_STREAM_UNREF(stream, "perform_stream_op");
return;
}
if (stream->is_closed) {
if (op->send_message) {
// Reset the send_message payload to prevent memory leaks.
op->payload->send_message.send_message->Clear();
}
if (op->recv_initial_metadata) {
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
op->payload->recv_initial_metadata.recv_initial_metadata_ready,
stream->cancel_self_error);
}
if (op->recv_message) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION,
op->payload->recv_message.recv_message_ready,
stream->cancel_self_error);
}
if (op->recv_trailing_metadata) {
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready,
stream->cancel_self_error);
}
if (op->on_complete != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_complete,
stream->cancel_self_error);
}
GRPC_BINDER_STREAM_UNREF(stream, "perform_stream_op");
return;
}
int tx_code = stream->tx_code;
auto tx =
std::make_unique<grpc_binder::Transaction>(tx_code, transport->is_client);
if (op->send_initial_metadata) {
LOG(INFO) << "send_initial_metadata";
grpc_binder::Metadata init_md;
auto batch = op->payload->send_initial_metadata.send_initial_metadata;
grpc_binder::MetadataEncoder encoder(transport->is_client, tx.get(),
&init_md);
batch->Encode(&encoder);
tx->SetPrefix(init_md);
}
if (op->send_message) {
LOG(INFO) << "send_message";
tx->SetData(op->payload->send_message.send_message->JoinIntoString());
}
if (op->send_trailing_metadata) {
LOG(INFO) << "send_trailing_metadata";
auto batch = op->payload->send_trailing_metadata.send_trailing_metadata;
grpc_binder::Metadata trailing_metadata;
grpc_binder::MetadataEncoder encoder(transport->is_client, tx.get(),
&trailing_metadata);
batch->Encode(&encoder);
// TODO(mingcl): Will we ever has key-value pair here? According to
// wireformat client suffix data is always empty.
tx->SetSuffix(trailing_metadata);
}
if (op->recv_initial_metadata) {
LOG(INFO) << "recv_initial_metadata";
stream->recv_initial_metadata_ready =
op->payload->recv_initial_metadata.recv_initial_metadata_ready;
stream->recv_initial_metadata =
op->payload->recv_initial_metadata.recv_initial_metadata;
stream->trailing_metadata_available =
op->payload->recv_initial_metadata.trailing_metadata_available;
GRPC_BINDER_STREAM_REF(stream, "recv_initial_metadata");
transport->transport_stream_receiver->RegisterRecvInitialMetadata(
tx_code, [tx_code, stream, transport](
absl::StatusOr<grpc_binder::Metadata> initial_metadata) {
grpc_core::ExecCtx exec_ctx;
stream->recv_initial_metadata_args.tx_code = tx_code;
stream->recv_initial_metadata_args.initial_metadata =
std::move(initial_metadata);
transport->combiner->Run(
GRPC_CLOSURE_INIT(&stream->recv_initial_metadata_closure,
recv_initial_metadata_locked,
&stream->recv_initial_metadata_args, nullptr),
absl::OkStatus());
});
}
if (op->recv_message) {
LOG(INFO) << "recv_message";
stream->recv_message_ready = op->payload->recv_message.recv_message_ready;
stream->recv_message = op->payload->recv_message.recv_message;
stream->call_failed_before_recv_message =
op->payload->recv_message.call_failed_before_recv_message;
if (op->payload->recv_message.flags != nullptr) {
*op->payload->recv_message.flags = 0;
}
GRPC_BINDER_STREAM_REF(stream, "recv_message");
transport->transport_stream_receiver->RegisterRecvMessage(
tx_code,
[tx_code, stream, transport](absl::StatusOr<std::string> message) {
grpc_core::ExecCtx exec_ctx;
stream->recv_message_args.tx_code = tx_code;
stream->recv_message_args.message = std::move(message);
transport->combiner->Run(
GRPC_CLOSURE_INIT(&stream->recv_message_closure,
recv_message_locked, &stream->recv_message_args,
nullptr),
absl::OkStatus());
});
}
if (op->recv_trailing_metadata) {
LOG(INFO) << "recv_trailing_metadata";
stream->recv_trailing_metadata_finished =
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready;
stream->recv_trailing_metadata =
op->payload->recv_trailing_metadata.recv_trailing_metadata;
GRPC_BINDER_STREAM_REF(stream, "recv_trailing_metadata");
transport->transport_stream_receiver->RegisterRecvTrailingMetadata(
tx_code, [tx_code, stream, transport](
absl::StatusOr<grpc_binder::Metadata> trailing_metadata,
int status) {
grpc_core::ExecCtx exec_ctx;
stream->recv_trailing_metadata_args.tx_code = tx_code;
stream->recv_trailing_metadata_args.trailing_metadata =
std::move(trailing_metadata);
stream->recv_trailing_metadata_args.status = status;
transport->combiner->Run(
GRPC_CLOSURE_INIT(&stream->recv_trailing_metadata_closure,
recv_trailing_metadata_locked,
&stream->recv_trailing_metadata_args, nullptr),
absl::OkStatus());
});
}
// Only send transaction when there's a send op presented.
absl::Status status;
if (op->send_initial_metadata || op->send_message ||
op->send_trailing_metadata) {
status = transport->wire_writer->RpcCall(std::move(tx));
if (!stream->is_client && op->send_trailing_metadata) {
stream->trailing_metadata_sent = true;
// According to transport explaineer - "Server extra: This op shouldn't
// actually be considered complete until the server has also sent trailing
// metadata to provide the other side with final status"
//
// Because we've done sending trailing metadata here, we can safely
// complete the recv_trailing_metadata callback here.
if (stream->need_to_call_trailing_metadata_callback) {
grpc_closure* cb = stream->recv_trailing_metadata_finished;
stream->recv_trailing_metadata_finished = nullptr;
grpc_core::ExecCtx::Run(DEBUG_LOCATION, cb, absl::OkStatus());
stream->need_to_call_trailing_metadata_callback = false;
}
}
}
// Note that this should only be scheduled when all non-recv ops are
// completed
if (op->on_complete != nullptr) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_complete,
absl_status_to_grpc_error(status));
LOG(INFO) << "on_complete closure scheduled";
}
GRPC_BINDER_STREAM_UNREF(stream, "perform_stream_op");
}
void grpc_binder_transport::PerformStreamOp(
grpc_stream* gs, grpc_transport_stream_op_batch* op) {
grpc_binder_stream* stream = reinterpret_cast<grpc_binder_stream*>(gs);
LOG(INFO) << __func__ << " = " << this << " " << gs << " " << op
<< " is_client = " << stream->is_client;
GRPC_BINDER_STREAM_REF(stream, "perform_stream_op");
op->handler_private.extra_arg = stream;
combiner->Run(GRPC_CLOSURE_INIT(&op->handler_private.closure,
perform_stream_op_locked, op, nullptr),
absl::OkStatus());
}
static void close_transport_locked(grpc_binder_transport* transport) {
transport->state_tracker.SetState(
GRPC_CHANNEL_SHUTDOWN, absl::OkStatus(),
"transport closed due to disconnection/goaway");
while (!transport->registered_stream.empty()) {
cancel_stream_locked(
transport, transport->registered_stream.begin()->second,
grpc_error_set_int(GRPC_ERROR_CREATE("transport closed"),
grpc_core::StatusIntProperty::kRpcStatus,
GRPC_STATUS_UNAVAILABLE));
}
}
static void perform_transport_op_locked(void* transport_op,
grpc_error_handle /*error*/) {
grpc_transport_op* op = static_cast<grpc_transport_op*>(transport_op);
grpc_binder_transport* transport =
static_cast<grpc_binder_transport*>(op->handler_private.extra_arg);
// TODO(waynetu): Should we lock here to avoid data race?
if (op->start_connectivity_watch != nullptr) {
transport->state_tracker.AddWatcher(
op->start_connectivity_watch_state,
std::move(op->start_connectivity_watch));
}
if (op->stop_connectivity_watch != nullptr) {
transport->state_tracker.RemoveWatcher(op->stop_connectivity_watch);
}
if (op->set_accept_stream) {
transport->accept_stream_user_data = op->set_accept_stream_user_data;
transport->accept_stream_fn = op->set_accept_stream_fn;
transport->registered_method_matcher_cb =
op->set_registered_method_matcher_fn;
VLOG(2) << "accept_stream_fn_called_count_ = "
<< transport->accept_stream_fn_called_count_;
while (transport->accept_stream_fn_called_count_ > 0) {
--transport->accept_stream_fn_called_count_;
transport->combiner->Run(
GRPC_CLOSURE_CREATE(accept_stream_locked, transport, nullptr),
absl::OkStatus());
}
}
if (op->on_consumed) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, absl::OkStatus());
}
bool do_close = false;
if (!op->disconnect_with_error.ok()) {
do_close = true;
}
if (!op->goaway_error.ok()) {
do_close = true;
}
if (do_close) {
close_transport_locked(transport);
}
GRPC_BINDER_UNREF_TRANSPORT(transport, "perform_transport_op");
}
void grpc_binder_transport::PerformOp(grpc_transport_op* op) {
LOG(INFO) << __func__;
op->handler_private.extra_arg = this;
GRPC_BINDER_REF_TRANSPORT(this, "perform_transport_op");
combiner->Run(GRPC_CLOSURE_INIT(&op->handler_private.closure,
perform_transport_op_locked, op, nullptr),
absl::OkStatus());
}
static void destroy_stream_locked(void* sp, grpc_error_handle /*error*/) {
grpc_binder_stream* stream = static_cast<grpc_binder_stream*>(sp);
grpc_binder_transport* transport = stream->t;
cancel_stream_locked(
transport, stream,
grpc_error_set_int(GRPC_ERROR_CREATE("destroy stream"),
grpc_core::StatusIntProperty::kRpcStatus,
GRPC_STATUS_UNAVAILABLE));
stream->~grpc_binder_stream();
}
void grpc_binder_transport::DestroyStream(grpc_stream* gs,
grpc_closure* then_schedule_closure) {
LOG(INFO) << __func__;
grpc_binder_stream* stream = reinterpret_cast<grpc_binder_stream*>(gs);
stream->destroy_stream_then_closure = then_schedule_closure;
stream->t->combiner->Run(
GRPC_CLOSURE_INIT(&stream->destroy_stream, destroy_stream_locked, stream,
nullptr),
absl::OkStatus());
}
static void destroy_transport_locked(void* gt, grpc_error_handle /*error*/) {
grpc_binder_transport* transport = static_cast<grpc_binder_transport*>(gt);
close_transport_locked(transport);
// Release the references held by the transport.
transport->wire_reader = nullptr;
transport->transport_stream_receiver = nullptr;
transport->wire_writer = nullptr;
GRPC_BINDER_UNREF_TRANSPORT(transport, "transport destroyed");
}
void grpc_binder_transport::Orphan() {
LOG(INFO) << __func__;
combiner->Run(GRPC_CLOSURE_CREATE(destroy_transport_locked, this, nullptr),
absl::OkStatus());
}
size_t grpc_binder_transport::SizeOfStream() const {
return sizeof(grpc_binder_stream);
}
grpc_binder_transport::grpc_binder_transport(
std::unique_ptr<grpc_binder::Binder> binder, bool is_client,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy)
: is_client(is_client),
combiner(grpc_combiner_create(
grpc_event_engine::experimental::GetDefaultEventEngine())),
state_tracker(
is_client ? "binder_transport_client" : "binder_transport_server",
GRPC_CHANNEL_READY),
refs(1, nullptr) {
LOG(INFO) << __func__;
transport_stream_receiver =
std::make_shared<grpc_binder::TransportStreamReceiverImpl>(
is_client, /*accept_stream_callback=*/[this] {
grpc_core::ExecCtx exec_ctx;
combiner->Run(
GRPC_CLOSURE_CREATE(accept_stream_locked, this, nullptr),
absl::OkStatus());
});
// WireReader holds a ref to grpc_binder_transport.
GRPC_BINDER_REF_TRANSPORT(this, "wire reader");
wire_reader = grpc_core::MakeOrphanable<grpc_binder::WireReaderImpl>(
transport_stream_receiver, is_client, security_policy,
// on_destruct_callback=
[this] {
// Unref transport when destructed.
GRPC_BINDER_UNREF_TRANSPORT(this, "wire reader");
});
wire_writer = wire_reader->SetupTransport(std::move(binder));
}
grpc_binder_transport::~grpc_binder_transport() {
GRPC_COMBINER_UNREF(combiner, "binder_transport");
}
grpc_core::Transport* grpc_create_binder_transport_client(
std::unique_ptr<grpc_binder::Binder> endpoint_binder,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
LOG(INFO) << __func__;
CHECK(endpoint_binder != nullptr);
CHECK_NE(security_policy, nullptr);
grpc_binder_transport* t = new grpc_binder_transport(
std::move(endpoint_binder), /*is_client=*/true, security_policy);
return t;
}
grpc_core::Transport* grpc_create_binder_transport_server(
std::unique_ptr<grpc_binder::Binder> client_binder,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy) {
LOG(INFO) << __func__;
CHECK(client_binder != nullptr);
CHECK_NE(security_policy, nullptr);
grpc_binder_transport* t = new grpc_binder_transport(
std::move(client_binder), /*is_client=*/false, security_policy);
return t;
}
#endif

@ -1,119 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_TRANSPORT_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_TRANSPORT_H
#include <grpc/support/port_platform.h>
#include <grpcpp/security/binder_security_policy.h>
#include <atomic>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/util/crash.h"
struct grpc_binder_stream;
// TODO(mingcl): Consider putting the struct in a namespace (Eventually this
// depends on what style we want to follow)
// TODO(mingcl): Decide casing for this class name. Should we use C-style class
// name here or just go with C++ style?
struct grpc_binder_transport final : public grpc_core::FilterStackTransport {
explicit grpc_binder_transport(
std::unique_ptr<grpc_binder::Binder> binder, bool is_client,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
~grpc_binder_transport() override;
grpc_core::FilterStackTransport* filter_stack_transport() override {
return this;
}
grpc_core::ClientTransport* client_transport() override { return nullptr; }
grpc_core::ServerTransport* server_transport() override { return nullptr; }
absl::string_view GetTransportName() const override { return "binder"; }
void InitStream(grpc_stream* gs, grpc_stream_refcount* refcount,
const void* server_data, grpc_core::Arena* arena) override;
void SetPollset(grpc_stream*, grpc_pollset*) override {}
void SetPollsetSet(grpc_stream*, grpc_pollset_set*) override {}
void PerformOp(grpc_transport_op* op) override;
size_t SizeOfStream() const override;
bool HackyDisableStreamOpBatchCoalescingInConnectedChannel() const override {
return false;
}
void PerformStreamOp(grpc_stream* gs,
grpc_transport_stream_op_batch* op) override;
void DestroyStream(grpc_stream* gs,
grpc_closure* then_schedule_closure) override;
void Orphan() override;
int NewStreamTxCode() {
// TODO(mingcl): Wrap around when all tx codes are used. "If we do detect a
// collision however, we will fail the new call with UNAVAILABLE, and shut
// down the transport gracefully."
CHECK(next_free_tx_code <= LAST_CALL_TRANSACTION);
return next_free_tx_code++;
}
std::shared_ptr<grpc_binder::TransportStreamReceiver>
transport_stream_receiver;
grpc_core::OrphanablePtr<grpc_binder::WireReader> wire_reader;
std::shared_ptr<grpc_binder::WireWriter> wire_writer;
bool is_client;
// A set of currently registered streams (the key is the stream ID).
absl::flat_hash_map<int, grpc_binder_stream*> registered_stream;
grpc_core::Combiner* combiner;
// The callback and the data for the callback when the stream is connected
// between client and server. registered_method_matcher_cb is called before
// invoking the recv initial metadata callback.
void (*accept_stream_fn)(void* user_data, grpc_core::Transport* transport,
const void* server_data) = nullptr;
void (*registered_method_matcher_cb)(
void* user_data, grpc_core::ServerMetadata* metadata) = nullptr;
void* accept_stream_user_data = nullptr;
// `accept_stream_locked()` could be called before `accept_stream_fn` has been
// set, we need to remember those requests that comes too early and call them
// later when we can.
int accept_stream_fn_called_count_{0};
grpc_core::ConnectivityStateTracker state_tracker;
grpc_core::RefCount refs;
private:
std::atomic<int> next_free_tx_code{grpc_binder::kFirstCallId};
};
grpc_core::Transport* grpc_create_binder_transport_client(
std::unique_ptr<grpc_binder::Binder> endpoint_binder,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
grpc_core::Transport* grpc_create_binder_transport_server(
std::unique_ptr<grpc_binder::Binder> client_binder,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy);
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_TRANSPORT_BINDER_TRANSPORT_H

@ -1,76 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_BINDER_AUTO_UTILS_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_BINDER_AUTO_UTILS_H
#include <grpc/support/port_platform.h>
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include "src/core/ext/transport/binder/utils/ndk_binder.h"
namespace grpc_binder {
namespace ndk_util {
///
/// Represents one strong pointer to an AIBinder object.
/// Copied from binder/ndk/include_cpp/android/binder_auto_utils.h
///
class SpAIBinder {
public:
SpAIBinder() : mBinder(nullptr) {}
explicit SpAIBinder(AIBinder* binder) : mBinder(binder) {}
SpAIBinder(std::nullptr_t)
: SpAIBinder() {} // NOLINT(google-explicit-constructor)
SpAIBinder(const SpAIBinder& other) { *this = other; }
~SpAIBinder() { set(nullptr); }
SpAIBinder& operator=(const SpAIBinder& other) {
if (this == &other) {
return *this;
}
AIBinder_incStrong(other.mBinder);
set(other.mBinder);
return *this;
}
void set(AIBinder* binder) {
AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder);
if (old != nullptr) AIBinder_decStrong(old);
if (old != *const_cast<AIBinder* volatile*>(&mBinder)) {
__assert(__FILE__, __LINE__, "Race detected.");
}
mBinder = binder;
}
AIBinder* get() const { return mBinder; }
AIBinder** getR() { return &mBinder; }
bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
private:
AIBinder* mBinder = nullptr;
};
} // namespace ndk_util
} // namespace grpc_binder
#endif
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_BINDER_AUTO_UTILS_H

@ -1,218 +0,0 @@
// 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/utils/ndk_binder.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <dlfcn.h>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/util/crash.h"
#include "src/core/util/sync.h"
namespace {
void* GetNdkBinderHandle() {
// TODO(mingcl): Consider using RTLD_NOLOAD to check if it is already loaded
// first
static void* handle = dlopen("libbinder_ndk.so", RTLD_LAZY);
if (handle == nullptr) {
LOG(ERROR) << "Cannot open libbinder_ndk.so. Does this device support API "
"level 29?";
CHECK(0);
}
return handle;
}
JavaVM* g_jvm = nullptr;
grpc_core::Mutex g_jvm_mu;
// Whether the thread has already attached to JVM (this is to prevent
// repeated attachment in `AttachJvm()`)
thread_local bool g_is_jvm_attached = false;
void SetJvm(JNIEnv* env) {
// OK to lock here since this function will only be called once for each
// connection.
grpc_core::MutexLock lock(&g_jvm_mu);
if (g_jvm != nullptr) {
return;
}
JavaVM* jvm = nullptr;
jint error = env->GetJavaVM(&jvm);
if (error != JNI_OK) {
LOG(ERROR) << "Failed to get JVM";
}
g_jvm = jvm;
LOG(INFO) << "JVM cached";
}
// `SetJvm` need to be called in the process before `AttachJvm`. This is always
// the case because one of `AIBinder_fromJavaBinder`/`AIBinder_toJavaBinder`
// will be called before we actually uses the binder. Return `false` if not able
// to attach to JVM. Return `true` if JVM is attached (or already attached).
bool AttachJvm() {
if (g_is_jvm_attached) {
return true;
}
// Note: The following code would be run at most once per thread.
grpc_core::MutexLock lock(&g_jvm_mu);
if (g_jvm == nullptr) {
LOG(ERROR) << "JVM not cached yet";
return false;
}
JNIEnv* env_unused;
// Note that attach a thread that is already attached is a no-op, so it is
// fine to call this again if the thread has already been attached by other.
g_jvm->AttachCurrentThread(&env_unused, /* thr_args= */ nullptr);
LOG(INFO) << "JVM attached successfully";
g_is_jvm_attached = true;
return true;
}
} // namespace
namespace grpc_binder {
namespace ndk_util {
// Helper macro to obtain the function pointer corresponding to the name
#define FORWARD(name) \
typedef decltype(&name) func_type; \
static func_type ptr = \
reinterpret_cast<func_type>(dlsym(GetNdkBinderHandle(), #name)); \
if (ptr == nullptr) { \
LOG(ERROR) << "dlsym failed. Cannot find " << #name \
<< " in libbinder_ndk.so. " \
<< "BinderTransport requires API level >= 33"; \
CHECK(0); \
} \
return ptr
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
FORWARD(AIBinder_Class_disableInterfaceTokenHeader)(clazz);
}
void* AIBinder_getUserData(AIBinder* binder) {
FORWARD(AIBinder_getUserData)(binder);
}
uid_t AIBinder_getCallingUid() { FORWARD(AIBinder_getCallingUid)(); }
AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
SetJvm(env);
FORWARD(AIBinder_fromJavaBinder)(env, binder);
}
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
AIBinder_Class_onTransact onTransact) {
FORWARD(AIBinder_Class_define)
(interfaceDescriptor, onCreate, onDestroy, onTransact);
}
AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
FORWARD(AIBinder_new)(clazz, args);
}
bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) {
FORWARD(AIBinder_associateClass)(binder, clazz);
}
void AIBinder_incStrong(AIBinder* binder) {
FORWARD(AIBinder_incStrong)(binder);
}
void AIBinder_decStrong(AIBinder* binder) {
FORWARD(AIBinder_decStrong)(binder);
}
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code,
AParcel** in, AParcel** out,
binder_flags_t flags) {
if (!AttachJvm()) {
LOG(ERROR) << "failed to attach JVM. AIBinder_transact might fail.";
}
FORWARD(AIBinder_transact)(binder, code, in, out, flags);
}
binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
AParcel_byteArrayAllocator allocator) {
FORWARD(AParcel_readByteArray)(parcel, arrayData, allocator);
}
void AParcel_delete(AParcel* parcel) { FORWARD(AParcel_delete)(parcel); }
int32_t AParcel_getDataSize(const AParcel* parcel) {
FORWARD(AParcel_getDataSize)(parcel);
}
binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) {
FORWARD(AParcel_writeInt32)(parcel, value);
}
binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) {
FORWARD(AParcel_writeInt64)(parcel, value);
}
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
FORWARD(AParcel_writeStrongBinder)(parcel, binder);
}
binder_status_t AParcel_writeString(AParcel* parcel, const char* string,
int32_t length) {
FORWARD(AParcel_writeString)(parcel, string, length);
}
binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) {
FORWARD(AParcel_readInt32)(parcel, value);
}
binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) {
FORWARD(AParcel_readInt64)(parcel, value);
}
binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
AParcel_stringAllocator allocator) {
FORWARD(AParcel_readString)(parcel, stringData, allocator);
}
binder_status_t AParcel_readStrongBinder(const AParcel* parcel,
AIBinder** binder) {
FORWARD(AParcel_readStrongBinder)(parcel, binder);
}
binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData,
int32_t length) {
FORWARD(AParcel_writeByteArray)(parcel, arrayData, length);
}
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
FORWARD(AIBinder_prepareTransaction)(binder, in);
}
jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) {
SetJvm(env);
FORWARD(AIBinder_toJavaBinder)(env, binder);
}
} // namespace ndk_util
} // namespace grpc_binder
#endif
#endif

@ -1,107 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_NDK_BINDER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_NDK_BINDER_H
#include <grpc/support/port_platform.h>
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <assert.h>
#include <jni.h>
#include <memory>
// This file defines NdkBinder functions, variables, and types in
// grpc_binder::ndk_util namespace. This allows us to dynamically load
// libbinder_ndk at runtime, and make it possible to compile the code without
// the library present at compile time.
// TODO(mingcl): Consider if we want to check API level and include NDK headers
// normally if the level is high enough
namespace grpc_binder {
namespace ndk_util {
struct AIBinder;
struct AParcel;
struct AIBinder_Class;
// Only enum values used by the project is defined here
enum {
FLAG_ONEWAY = 0x01,
};
enum {
STATUS_OK = 0,
STATUS_UNKNOWN_ERROR = (-2147483647 - 1),
};
typedef int32_t binder_status_t;
typedef uint32_t binder_flags_t;
typedef uint32_t transaction_code_t;
typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length,
int8_t** outBuffer);
typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length,
char** buffer);
typedef void* (*AIBinder_Class_onCreate)(void* args);
typedef void (*AIBinder_Class_onDestroy)(void* userData);
typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder,
transaction_code_t code,
const AParcel* in,
AParcel* out);
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz);
void* AIBinder_getUserData(AIBinder* binder);
uid_t AIBinder_getCallingUid();
AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder);
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
AIBinder_Class_onTransact onTransact);
AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args);
bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz);
void AIBinder_incStrong(AIBinder* binder);
void AIBinder_decStrong(AIBinder* binder);
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code,
AParcel** in, AParcel** out,
binder_flags_t flags);
binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
AParcel_byteArrayAllocator allocator);
void AParcel_delete(AParcel* parcel);
int32_t AParcel_getDataSize(const AParcel* parcel);
binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value);
binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value);
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder);
binder_status_t AParcel_writeString(AParcel* parcel, const char* string,
int32_t length);
binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value);
binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value);
binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
AParcel_stringAllocator allocator);
binder_status_t AParcel_readStrongBinder(const AParcel* parcel,
AIBinder** binder);
binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData,
int32_t length);
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in);
jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder);
} // namespace ndk_util
} // namespace grpc_binder
#endif // GPR_SUPPORT_BINDER_TRANSPORT
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_NDK_BINDER_H

@ -1,70 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_H
#include <grpc/support/port_platform.h>
#include <functional>
#include <string>
#include <vector>
#include "absl/status/statusor.h"
#include "src/core/ext/transport/binder/wire_format/transaction.h"
namespace grpc_binder {
typedef int StreamIdentifier;
class TransportStreamReceiver {
public:
virtual ~TransportStreamReceiver() = default;
using InitialMetadataCallbackType =
std::function<void(absl::StatusOr<Metadata>)>;
using MessageDataCallbackType =
std::function<void(absl::StatusOr<std::string>)>;
using TrailingMetadataCallbackType =
std::function<void(absl::StatusOr<Metadata>, int)>;
// Only handles single time invocation. Callback object will be deleted.
// The callback should be valid until invocation or unregister.
virtual void RegisterRecvInitialMetadata(StreamIdentifier id,
InitialMetadataCallbackType cb) = 0;
virtual void RegisterRecvMessage(StreamIdentifier id,
MessageDataCallbackType cb) = 0;
virtual void RegisterRecvTrailingMetadata(
StreamIdentifier id, TrailingMetadataCallbackType cb) = 0;
// For the following functions, the second arguments are the transaction
// result received from the lower level. If it is None, that means there's
// something wrong when receiving the corresponding transaction. In such case,
// we should cancel the gRPC callback as well.
virtual void NotifyRecvInitialMetadata(
StreamIdentifier id, absl::StatusOr<Metadata> initial_metadata) = 0;
virtual void NotifyRecvMessage(StreamIdentifier id,
absl::StatusOr<std::string> message) = 0;
virtual void NotifyRecvTrailingMetadata(
StreamIdentifier id, absl::StatusOr<Metadata> trailing_metadata,
int status) = 0;
// Remove all entries associated with stream number `id`.
virtual void CancelStream(StreamIdentifier id) = 0;
static const absl::string_view kGrpcBinderTransportCancelledGracefully;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_H

@ -1,257 +0,0 @@
// 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/utils/transport_stream_receiver_impl.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <functional>
#include <string>
#include <utility>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "src/core/util/crash.h"
namespace grpc_binder {
const absl::string_view
TransportStreamReceiver::kGrpcBinderTransportCancelledGracefully =
"grpc-binder-transport: cancelled gracefully";
void TransportStreamReceiverImpl::RegisterRecvInitialMetadata(
StreamIdentifier id, InitialMetadataCallbackType cb) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
absl::StatusOr<Metadata> initial_metadata{};
{
grpc_core::MutexLock l(&m_);
CHECK_EQ(initial_metadata_cbs_.count(id), 0u);
auto iter = pending_initial_metadata_.find(id);
if (iter == pending_initial_metadata_.end()) {
if (trailing_metadata_recvd_.count(id)) {
cb(absl::CancelledError(""));
} else {
initial_metadata_cbs_[id] = std::move(cb);
}
cb = nullptr;
} else {
initial_metadata = std::move(iter->second.front());
iter->second.pop();
if (iter->second.empty()) {
pending_initial_metadata_.erase(iter);
}
}
}
if (cb != nullptr) {
cb(std::move(initial_metadata));
}
}
void TransportStreamReceiverImpl::RegisterRecvMessage(
StreamIdentifier id, MessageDataCallbackType cb) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
absl::StatusOr<std::string> message{};
{
grpc_core::MutexLock l(&m_);
CHECK_EQ(message_cbs_.count(id), 0u);
auto iter = pending_message_.find(id);
if (iter == pending_message_.end()) {
// If we'd already received trailing-metadata and there's no pending
// messages, cancel the callback.
if (trailing_metadata_recvd_.count(id)) {
cb(absl::CancelledError(
TransportStreamReceiver::kGrpcBinderTransportCancelledGracefully));
} else {
message_cbs_[id] = std::move(cb);
}
cb = nullptr;
} else {
// We'll still keep all pending messages received before the trailing
// metadata since they're issued before the end of stream, as promised by
// WireReader which keeps transactions commit in-order.
message = std::move(iter->second.front());
iter->second.pop();
if (iter->second.empty()) {
pending_message_.erase(iter);
}
}
}
if (cb != nullptr) {
cb(std::move(message));
}
}
void TransportStreamReceiverImpl::RegisterRecvTrailingMetadata(
StreamIdentifier id, TrailingMetadataCallbackType cb) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
std::pair<absl::StatusOr<Metadata>, int> trailing_metadata{};
{
grpc_core::MutexLock l(&m_);
CHECK_EQ(trailing_metadata_cbs_.count(id), 0u);
auto iter = pending_trailing_metadata_.find(id);
if (iter == pending_trailing_metadata_.end()) {
trailing_metadata_cbs_[id] = std::move(cb);
cb = nullptr;
} else {
trailing_metadata = std::move(iter->second.front());
iter->second.pop();
if (iter->second.empty()) {
pending_trailing_metadata_.erase(iter);
}
}
}
if (cb != nullptr) {
cb(std::move(trailing_metadata.first), trailing_metadata.second);
}
}
void TransportStreamReceiverImpl::NotifyRecvInitialMetadata(
StreamIdentifier id, absl::StatusOr<Metadata> initial_metadata) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
if (!is_client_ && accept_stream_callback_ && initial_metadata.ok()) {
accept_stream_callback_();
}
InitialMetadataCallbackType cb;
{
grpc_core::MutexLock l(&m_);
auto iter = initial_metadata_cbs_.find(id);
if (iter != initial_metadata_cbs_.end()) {
cb = iter->second;
initial_metadata_cbs_.erase(iter);
} else {
pending_initial_metadata_[id].push(std::move(initial_metadata));
return;
}
}
cb(std::move(initial_metadata));
}
void TransportStreamReceiverImpl::NotifyRecvMessage(
StreamIdentifier id, absl::StatusOr<std::string> message) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
MessageDataCallbackType cb;
{
grpc_core::MutexLock l(&m_);
auto iter = message_cbs_.find(id);
if (iter != message_cbs_.end()) {
cb = iter->second;
message_cbs_.erase(iter);
} else {
pending_message_[id].push(std::move(message));
return;
}
}
cb(std::move(message));
}
void TransportStreamReceiverImpl::NotifyRecvTrailingMetadata(
StreamIdentifier id, absl::StatusOr<Metadata> trailing_metadata,
int status) {
// Trailing metadata mark the end of the stream. Since TransportStreamReceiver
// assumes in-order commitments of transactions and that trailing metadata is
// parsed after message data, we can safely cancel all upcoming callbacks of
// recv_message.
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
OnRecvTrailingMetadata(id);
TrailingMetadataCallbackType cb;
{
grpc_core::MutexLock l(&m_);
auto iter = trailing_metadata_cbs_.find(id);
if (iter != trailing_metadata_cbs_.end()) {
cb = iter->second;
trailing_metadata_cbs_.erase(iter);
} else {
pending_trailing_metadata_[id].emplace(std::move(trailing_metadata),
status);
return;
}
}
cb(std::move(trailing_metadata), status);
}
void TransportStreamReceiverImpl::CancelInitialMetadataCallback(
StreamIdentifier id, absl::Status error) {
InitialMetadataCallbackType callback = nullptr;
{
grpc_core::MutexLock l(&m_);
auto iter = initial_metadata_cbs_.find(id);
if (iter != initial_metadata_cbs_.end()) {
callback = std::move(iter->second);
initial_metadata_cbs_.erase(iter);
}
}
if (callback != nullptr) {
std::move(callback)(error);
}
}
void TransportStreamReceiverImpl::CancelMessageCallback(StreamIdentifier id,
absl::Status error) {
MessageDataCallbackType callback = nullptr;
{
grpc_core::MutexLock l(&m_);
auto iter = message_cbs_.find(id);
if (iter != message_cbs_.end()) {
callback = std::move(iter->second);
message_cbs_.erase(iter);
}
}
if (callback != nullptr) {
std::move(callback)(error);
}
}
void TransportStreamReceiverImpl::CancelTrailingMetadataCallback(
StreamIdentifier id, absl::Status error) {
TrailingMetadataCallbackType callback = nullptr;
{
grpc_core::MutexLock l(&m_);
auto iter = trailing_metadata_cbs_.find(id);
if (iter != trailing_metadata_cbs_.end()) {
callback = std::move(iter->second);
trailing_metadata_cbs_.erase(iter);
}
}
if (callback != nullptr) {
std::move(callback)(error, 0);
}
}
void TransportStreamReceiverImpl::OnRecvTrailingMetadata(StreamIdentifier id) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
m_.Lock();
trailing_metadata_recvd_.insert(id);
m_.Unlock();
CancelInitialMetadataCallback(id, absl::CancelledError(""));
CancelMessageCallback(
id,
absl::CancelledError(
TransportStreamReceiver::kGrpcBinderTransportCancelledGracefully));
}
void TransportStreamReceiverImpl::CancelStream(StreamIdentifier id) {
LOG(INFO) << __func__ << " id = " << id << " is_client = " << is_client_;
CancelInitialMetadataCallback(id, absl::CancelledError("Stream cancelled"));
CancelMessageCallback(id, absl::CancelledError("Stream cancelled"));
CancelTrailingMetadataCallback(id, absl::CancelledError("Stream cancelled"));
grpc_core::MutexLock l(&m_);
trailing_metadata_recvd_.erase(id);
pending_initial_metadata_.erase(id);
pending_message_.erase(id);
pending_trailing_metadata_.erase(id);
}
} // namespace grpc_binder
#endif

@ -1,112 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_IMPL_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_IMPL_H
#include <grpc/support/port_platform.h>
#include <functional>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/util/sync.h"
namespace grpc_binder {
// Routes the data received from transport to corresponding streams
class TransportStreamReceiverImpl : public TransportStreamReceiver {
public:
explicit TransportStreamReceiverImpl(
bool is_client, std::function<void()> accept_stream_callback = nullptr)
: is_client_(is_client),
accept_stream_callback_(accept_stream_callback) {}
void RegisterRecvInitialMetadata(StreamIdentifier id,
InitialMetadataCallbackType cb) override;
void RegisterRecvMessage(StreamIdentifier id,
MessageDataCallbackType cb) override;
void RegisterRecvTrailingMetadata(StreamIdentifier id,
TrailingMetadataCallbackType cb) override;
void NotifyRecvInitialMetadata(
StreamIdentifier id, absl::StatusOr<Metadata> initial_metadata) override;
void NotifyRecvMessage(StreamIdentifier id,
absl::StatusOr<std::string> message) override;
void NotifyRecvTrailingMetadata(StreamIdentifier id,
absl::StatusOr<Metadata> trailing_metadata,
int status) override;
void CancelStream(StreamIdentifier id) override;
private:
// Trailing metadata marks the end of one-side of the stream. Thus, after
// receiving trailing metadata from the other-end, we know that there will
// never be in-coming message data anymore, and all recv_message callbacks
// (as well as recv_initial_metadata callback, if there's any) registered will
// never be satisfied. This function cancels all such callbacks gracefully
// (with absl::OkStatus()) to avoid being blocked waiting for them.
void OnRecvTrailingMetadata(StreamIdentifier id);
void CancelInitialMetadataCallback(StreamIdentifier id, absl::Status error);
void CancelMessageCallback(StreamIdentifier id, absl::Status error);
void CancelTrailingMetadataCallback(StreamIdentifier id, absl::Status error);
std::map<StreamIdentifier, InitialMetadataCallbackType> initial_metadata_cbs_;
std::map<StreamIdentifier, MessageDataCallbackType> message_cbs_;
std::map<StreamIdentifier, TrailingMetadataCallbackType>
trailing_metadata_cbs_;
// TODO(waynetu): Better thread safety design. For example, use separate
// mutexes for different type of messages.
grpc_core::Mutex m_;
// TODO(waynetu): gRPC surface layer will not wait for the current message to
// be delivered before sending the next message. The following implementation
// is still buggy with the current implementation of wire writer if
// transaction issued first completes after the one issued later does. This is
// because we just take the first element out of the queue and assume it's the
// one issued first without further checking, which results in callbacks being
// invoked with incorrect data.
//
// This should be fixed in the wire writer level and make sure out-of-order
// messages will be re-ordered by it. In such case, the queueing approach will
// work fine. Refer to the TODO in WireWriterImpl::ProcessTransaction() at
// wire_reader_impl.cc for detecting and resolving out-of-order transactions.
//
// TODO(waynetu): Use absl::flat_hash_map.
std::map<StreamIdentifier, std::queue<absl::StatusOr<Metadata>>>
pending_initial_metadata_ ABSL_GUARDED_BY(m_);
std::map<StreamIdentifier, std::queue<absl::StatusOr<std::string>>>
pending_message_ ABSL_GUARDED_BY(m_);
std::map<StreamIdentifier,
std::queue<std::pair<absl::StatusOr<Metadata>, int>>>
pending_trailing_metadata_ ABSL_GUARDED_BY(m_);
// Record whether or not the recv_message callbacks of a given stream is
// cancelled. Although we explicitly cancel the registered recv_message() in
// CancelRecvMessageCallbacksDueToTrailingMetadata(), there are chances that
// the registration comes "after" we receive trailing metadata. Therefore,
// when RegisterRecvMessage() gets called, we should check whether
// recv_message_cancelled_ contains the corresponding stream ID, and if so,
// directly cancel the callback gracefully without pending it.
std::set<StreamIdentifier> trailing_metadata_recvd_ ABSL_GUARDED_BY(m_);
bool is_client_;
// Called when receiving initial metadata to inform the server about a new
// stream.
std::function<void()> accept_stream_callback_;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_UTILS_TRANSPORT_STREAM_RECEIVER_IMPL_H

@ -1,104 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_H
#include <grpc/support/port_platform.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "src/core/ext/transport/binder/wire_format/binder_constants.h"
#include "src/core/util/orphanable.h"
namespace grpc_binder {
class HasRawBinder {
public:
virtual ~HasRawBinder() = default;
virtual void* GetRawBinder() = 0;
};
class Binder;
// TODO(waynetu): We might need other methods as well.
// TODO(waynetu): Find a better way to express the returned status than
// binder_status_t.
class WritableParcel {
public:
virtual ~WritableParcel() = default;
virtual int32_t GetDataSize() const = 0;
virtual absl::Status WriteInt32(int32_t data) = 0;
virtual absl::Status WriteInt64(int64_t data) = 0;
virtual absl::Status WriteBinder(HasRawBinder* binder) = 0;
virtual absl::Status WriteString(absl::string_view s) = 0;
virtual absl::Status WriteByteArray(const int8_t* buffer, int32_t length) = 0;
absl::Status WriteByteArrayWithLength(absl::string_view buffer) {
absl::Status status = WriteInt32(buffer.length());
if (!status.ok()) return status;
if (buffer.empty()) return absl::OkStatus();
return WriteByteArray(reinterpret_cast<const int8_t*>(buffer.data()),
buffer.length());
}
};
// TODO(waynetu): We might need other methods as well.
// TODO(waynetu): Find a better way to express the returned status than
// binder_status_t.
class ReadableParcel {
public:
virtual ~ReadableParcel() = default;
virtual int32_t GetDataSize() const = 0;
virtual absl::Status ReadInt32(int32_t* data) = 0;
virtual absl::Status ReadInt64(int64_t* data) = 0;
virtual absl::Status ReadBinder(std::unique_ptr<Binder>* data) = 0;
virtual absl::Status ReadByteArray(std::string* data) = 0;
virtual absl::Status ReadString(std::string* str) = 0;
};
class TransactionReceiver : public HasRawBinder {
public:
using OnTransactCb =
std::function<absl::Status(transaction_code_t, ReadableParcel*, int uid)>;
~TransactionReceiver() override = default;
};
class WireReader;
class Binder : public HasRawBinder {
public:
~Binder() override = default;
virtual void Initialize() = 0;
virtual absl::Status PrepareTransaction() = 0;
virtual absl::Status Transact(BinderTransportTxCode tx_code) = 0;
virtual WritableParcel* GetWritableParcel() const = 0;
// TODO(waynetu): Can we decouple the receiver from the binder?
virtual std::unique_ptr<TransactionReceiver> ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb transact_cb) const = 0;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_H

@ -1,308 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <map>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "src/core/ext/transport/binder/wire_format/binder_android.h"
#include "src/core/util/crash.h"
#include "src/core/util/sync.h"
namespace grpc_binder {
namespace {
struct BinderUserData {
explicit BinderUserData(grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb* callback)
: wire_reader_ref(wire_reader_ref), callback(callback) {}
grpc_core::RefCountedPtr<WireReader> wire_reader_ref;
TransactionReceiver::OnTransactCb* callback;
};
struct OnCreateArgs {
grpc_core::RefCountedPtr<WireReader> wire_reader_ref;
TransactionReceiver::OnTransactCb* callback;
};
void* f_onCreate_userdata(void* data) {
auto* args = static_cast<OnCreateArgs*>(data);
return new BinderUserData(args->wire_reader_ref, args->callback);
}
void f_onDestroy_delete(void* data) {
auto* user_data = static_cast<BinderUserData*>(data);
delete user_data;
}
void* f_onCreate_noop(void* /*args*/) { return nullptr; }
void f_onDestroy_noop(void* /*userData*/) {}
// TODO(mingcl): Consider if thread safety is a requirement here
ndk_util::binder_status_t f_onTransact(ndk_util::AIBinder* binder,
transaction_code_t code,
const ndk_util::AParcel* in,
ndk_util::AParcel* /*out*/) {
LOG(INFO) << __func__;
LOG(INFO) << "tx code = " << code;
auto* user_data =
static_cast<BinderUserData*>(ndk_util::AIBinder_getUserData(binder));
TransactionReceiver::OnTransactCb* callback = user_data->callback;
// Wrap the parcel in a ReadableParcel.
std::unique_ptr<ReadableParcel> output =
std::make_unique<ReadableParcelAndroid>(in);
// The lock should be released "after" the callback finishes.
absl::Status status =
(*callback)(code, output.get(), ndk_util::AIBinder_getCallingUid());
if (status.ok()) {
return ndk_util::STATUS_OK;
} else {
LOG(ERROR) << "Callback failed: " << status.ToString();
return ndk_util::STATUS_UNKNOWN_ERROR;
}
}
// StdStringAllocator, ReadString, StdVectorAllocator, and ReadVector's
// implementations are copied from android/binder_parcel_utils.h
// We cannot include the header because it does not compile in C++11
bool StdStringAllocator(void* stringData, int32_t length, char** buffer) {
if (length <= 0) return false;
std::string* str = static_cast<std::string*>(stringData);
str->resize(static_cast<size_t>(length) - 1);
*buffer = &(*str)[0];
return true;
}
ndk_util::binder_status_t AParcelReadString(const ndk_util::AParcel* parcel,
std::string* str) {
void* stringData = static_cast<void*>(str);
return ndk_util::AParcel_readString(parcel, stringData, StdStringAllocator);
}
template <typename T>
bool StdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) {
if (length < 0) return false;
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
if (static_cast<size_t>(length) > vec->max_size()) return false;
vec->resize(static_cast<size_t>(length));
*outBuffer = vec->data();
return true;
}
ndk_util::binder_status_t AParcelReadVector(const ndk_util::AParcel* parcel,
std::vector<uint8_t>* vec) {
void* vectorData = static_cast<void*>(vec);
return ndk_util::AParcel_readByteArray(parcel, vectorData,
StdVectorAllocator<int8_t>);
}
} // namespace
ndk_util::SpAIBinder FromJavaBinder(JNIEnv* jni_env, jobject binder) {
return ndk_util::SpAIBinder(
ndk_util::AIBinder_fromJavaBinder(jni_env, binder));
}
TransactionReceiverAndroid::TransactionReceiverAndroid(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
OnTransactCb transact_cb)
: transact_cb_(transact_cb) {
// TODO(mingcl): For now interface descriptor is always empty, figure out if
// we want it to be something more meaningful (we can probably manually change
// interface descriptor by modifying Java code's reply to
// os.IBinder.INTERFACE_TRANSACTION)
ndk_util::AIBinder_Class* aibinder_class = ndk_util::AIBinder_Class_define(
/*interfaceDescriptor=*/"", f_onCreate_userdata, f_onDestroy_delete,
f_onTransact);
ndk_util::AIBinder_Class_disableInterfaceTokenHeader(aibinder_class);
// Pass the on-transact callback to the on-create function of the binder. The
// on-create function equips the callback with a mutex and gives it to the
// user data stored in the binder which can be retrieved later.
// Also Ref() (called implicitly by the copy constructor of RefCountedPtr) the
// wire reader so that it would not be destructed during the callback
// invocation.
OnCreateArgs args;
args.wire_reader_ref = wire_reader_ref;
args.callback = &transact_cb_;
binder_ = ndk_util::AIBinder_new(aibinder_class, &args);
CHECK(binder_);
LOG(INFO) << "ndk_util::AIBinder_associateClass = "
<< ndk_util::AIBinder_associateClass(binder_, aibinder_class);
}
TransactionReceiverAndroid::~TransactionReceiverAndroid() {
// Release the binder.
ndk_util::AIBinder_decStrong(binder_);
}
namespace {
ndk_util::binder_status_t f_onTransact_noop(ndk_util::AIBinder* /*binder*/,
transaction_code_t /*code*/,
const ndk_util::AParcel* /*in*/,
ndk_util::AParcel* /*out*/) {
return {};
}
void AssociateWithNoopClass(ndk_util::AIBinder* binder) {
// Need to associate class before using it
ndk_util::AIBinder_Class* aibinder_class = ndk_util::AIBinder_Class_define(
"", f_onCreate_noop, f_onDestroy_noop, f_onTransact_noop);
ndk_util::AIBinder_Class_disableInterfaceTokenHeader(aibinder_class);
LOG(INFO) << "ndk_util::AIBinder_associateClass = "
<< ndk_util::AIBinder_associateClass(binder, aibinder_class);
}
} // namespace
void BinderAndroid::Initialize() {
ndk_util::AIBinder* binder = binder_.get();
AssociateWithNoopClass(binder);
}
absl::Status BinderAndroid::PrepareTransaction() {
ndk_util::AIBinder* binder = binder_.get();
return ndk_util::AIBinder_prepareTransaction(
binder, &input_parcel_->parcel_) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError(
"ndk_util::AIBinder_prepareTransaction failed");
}
absl::Status BinderAndroid::Transact(BinderTransportTxCode tx_code) {
ndk_util::AIBinder* binder = binder_.get();
// We only do one-way transaction and thus the output parcel is never used.
ndk_util::AParcel* unused_output_parcel;
absl::Status result =
(ndk_util::AIBinder_transact(
binder, static_cast<transaction_code_t>(tx_code),
&input_parcel_->parcel_, &unused_output_parcel,
ndk_util::FLAG_ONEWAY) == ndk_util::STATUS_OK)
? absl::OkStatus()
: absl::InternalError("ndk_util::AIBinder_transact failed");
ndk_util::AParcel_delete(unused_output_parcel);
return result;
}
std::unique_ptr<TransactionReceiver> BinderAndroid::ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb transact_cb) const {
return std::make_unique<TransactionReceiverAndroid>(wire_reader_ref,
transact_cb);
}
int32_t WritableParcelAndroid::GetDataSize() const {
return ndk_util::AParcel_getDataSize(parcel_);
}
absl::Status WritableParcelAndroid::WriteInt32(int32_t data) {
return ndk_util::AParcel_writeInt32(parcel_, data) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_writeInt32 failed");
}
absl::Status WritableParcelAndroid::WriteInt64(int64_t data) {
return ndk_util::AParcel_writeInt64(parcel_, data) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_writeInt64 failed");
}
absl::Status WritableParcelAndroid::WriteBinder(HasRawBinder* binder) {
return ndk_util::AParcel_writeStrongBinder(
parcel_, reinterpret_cast<ndk_util::AIBinder*>(
binder->GetRawBinder())) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_writeStrongBinder failed");
}
absl::Status WritableParcelAndroid::WriteString(absl::string_view s) {
return ndk_util::AParcel_writeString(parcel_, s.data(), s.length()) ==
ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_writeString failed");
}
absl::Status WritableParcelAndroid::WriteByteArray(const int8_t* buffer,
int32_t length) {
return ndk_util::AParcel_writeByteArray(parcel_, buffer, length) ==
ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_writeByteArray failed");
}
int32_t ReadableParcelAndroid::GetDataSize() const {
return ndk_util::AParcel_getDataSize(parcel_);
}
absl::Status ReadableParcelAndroid::ReadInt32(int32_t* data) {
return ndk_util::AParcel_readInt32(parcel_, data) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_readInt32 failed");
}
absl::Status ReadableParcelAndroid::ReadInt64(int64_t* data) {
return ndk_util::AParcel_readInt64(parcel_, data) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_readInt64 failed");
}
absl::Status ReadableParcelAndroid::ReadBinder(std::unique_ptr<Binder>* data) {
ndk_util::AIBinder* binder;
if (AParcel_readStrongBinder(parcel_, &binder) != ndk_util::STATUS_OK) {
*data = nullptr;
return absl::InternalError("AParcel_readStrongBinder failed");
}
*data = std::make_unique<BinderAndroid>(ndk_util::SpAIBinder(binder));
return absl::OkStatus();
}
absl::Status ReadableParcelAndroid::ReadByteArray(std::string* data) {
std::vector<uint8_t> vec;
if (AParcelReadVector(parcel_, &vec) == ndk_util::STATUS_OK) {
data->resize(vec.size());
if (!vec.empty()) {
memcpy(&((*data)[0]), vec.data(), vec.size());
}
return absl::OkStatus();
}
return absl::InternalError("AParcel_readByteArray failed");
}
absl::Status ReadableParcelAndroid::ReadString(std::string* str) {
return AParcelReadString(parcel_, str) == ndk_util::STATUS_OK
? absl::OkStatus()
: absl::InternalError("AParcel_readString failed");
}
} // namespace grpc_binder
#endif // GPR_SUPPORT_BINDER_TRANSPORT
#endif

@ -1,121 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_ANDROID_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_ANDROID_H
#include <grpc/support/port_platform.h>
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
#include <jni.h>
#include <memory>
#include "absl/memory/memory.h"
#include "src/core/ext/transport/binder/utils/binder_auto_utils.h"
#include "src/core/ext/transport/binder/utils/ndk_binder.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
namespace grpc_binder {
ndk_util::SpAIBinder FromJavaBinder(JNIEnv* jni_env, jobject binder);
class BinderAndroid;
class WritableParcelAndroid final : public WritableParcel {
public:
WritableParcelAndroid() = default;
explicit WritableParcelAndroid(ndk_util::AParcel* parcel) : parcel_(parcel) {}
~WritableParcelAndroid() override = default;
int32_t GetDataSize() const override;
absl::Status WriteInt32(int32_t data) override;
absl::Status WriteInt64(int64_t data) override;
absl::Status WriteBinder(HasRawBinder* binder) override;
absl::Status WriteString(absl::string_view s) override;
absl::Status WriteByteArray(const int8_t* buffer, int32_t length) override;
private:
ndk_util::AParcel* parcel_ = nullptr;
friend class BinderAndroid;
};
class ReadableParcelAndroid final : public ReadableParcel {
public:
ReadableParcelAndroid() = default;
// TODO(waynetu): Get rid of the const_cast.
explicit ReadableParcelAndroid(const ndk_util::AParcel* parcel)
: parcel_(parcel) {}
~ReadableParcelAndroid() override = default;
int32_t GetDataSize() const override;
absl::Status ReadInt32(int32_t* data) override;
absl::Status ReadInt64(int64_t* data) override;
absl::Status ReadBinder(std::unique_ptr<Binder>* data) override;
absl::Status ReadByteArray(std::string* data) override;
absl::Status ReadString(std::string* str) override;
private:
const ndk_util::AParcel* parcel_ = nullptr;
friend class BinderAndroid;
};
class BinderAndroid final : public Binder {
public:
explicit BinderAndroid(ndk_util::SpAIBinder binder)
: binder_(binder),
input_parcel_(std::make_unique<WritableParcelAndroid>()) {}
~BinderAndroid() override = default;
void* GetRawBinder() override { return binder_.get(); }
void Initialize() override;
absl::Status PrepareTransaction() override;
absl::Status Transact(BinderTransportTxCode tx_code) override;
WritableParcel* GetWritableParcel() const override {
return input_parcel_.get();
}
std::unique_ptr<TransactionReceiver> ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb transact_cb) const override;
private:
ndk_util::SpAIBinder binder_;
std::unique_ptr<WritableParcelAndroid> input_parcel_;
};
class TransactionReceiverAndroid final : public TransactionReceiver {
public:
TransactionReceiverAndroid(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
OnTransactCb transaction_cb);
~TransactionReceiverAndroid() override;
void* GetRawBinder() override { return binder_; }
private:
ndk_util::AIBinder* binder_;
OnTransactCb transact_cb_;
};
} // namespace grpc_binder
#endif // GPR_SUPPORT_BINDER_TRANSPORT
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_ANDROID_H

@ -1,29 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include "src/core/ext/transport/binder/wire_format/binder_constants.h"
ABSL_CONST_INIT const int FIRST_CALL_TRANSACTION = 0x00000001;
ABSL_CONST_INIT const int LAST_CALL_TRANSACTION = 0x00FFFFFF;
namespace grpc_binder {
ABSL_CONST_INIT const int kFirstCallId = FIRST_CALL_TRANSACTION + 1000;
} // namespace grpc_binder
#endif

@ -1,43 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_CONSTANTS_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_CONSTANTS_H
#include <grpc/support/port_platform.h>
#include <cstdint>
#include "absl/base/attributes.h"
using transaction_code_t = uint32_t;
ABSL_CONST_INIT extern const int FIRST_CALL_TRANSACTION;
ABSL_CONST_INIT extern const int LAST_CALL_TRANSACTION;
namespace grpc_binder {
enum class BinderTransportTxCode : int32_t {
SETUP_TRANSPORT = 1,
SHUTDOWN_TRANSPORT = 2,
ACKNOWLEDGE_BYTES = 3,
PING = 4,
PING_RESPONSE = 5,
};
ABSL_CONST_INIT extern const int kFirstCallId;
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_BINDER_CONSTANTS_H

@ -1,33 +0,0 @@
// 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 <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include "src/core/ext/transport/binder/wire_format/transaction.h"
namespace grpc_binder {
ABSL_CONST_INIT const int kFlagPrefix = 0x1;
ABSL_CONST_INIT const int kFlagMessageData = 0x2;
ABSL_CONST_INIT const int kFlagSuffix = 0x4;
ABSL_CONST_INIT const int kFlagOutOfBandClose = 0x8;
ABSL_CONST_INIT const int kFlagExpectSingleMessage = 0x10;
ABSL_CONST_INIT const int kFlagStatusDescription = 0x20;
ABSL_CONST_INIT const int kFlagMessageDataIsParcelable = 0x40;
ABSL_CONST_INIT const int kFlagMessageDataIsPartial = 0x80;
} // namespace grpc_binder
#endif

@ -1,106 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_TRANSACTION_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_TRANSACTION_H
#include <grpc/support/port_platform.h>
#include <string>
#include <vector>
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/strings/string_view.h"
#include "src/core/util/crash.h"
namespace grpc_binder {
ABSL_CONST_INIT extern const int kFlagPrefix;
ABSL_CONST_INIT extern const int kFlagMessageData;
ABSL_CONST_INIT extern const int kFlagSuffix;
ABSL_CONST_INIT extern const int kFlagOutOfBandClose;
ABSL_CONST_INIT extern const int kFlagExpectSingleMessage;
ABSL_CONST_INIT extern const int kFlagStatusDescription;
ABSL_CONST_INIT extern const int kFlagMessageDataIsParcelable;
ABSL_CONST_INIT extern const int kFlagMessageDataIsPartial;
using Metadata = std::vector<std::pair<std::string, std::string>>;
class Transaction {
public:
Transaction(int tx_code, bool is_client)
: tx_code_(tx_code), is_client_(is_client) {}
// TODO(mingcl): Consider using string_view
void SetPrefix(Metadata prefix_metadata) {
prefix_metadata_ = prefix_metadata;
CHECK_EQ((flags_ & kFlagPrefix), 0);
flags_ |= kFlagPrefix;
}
void SetMethodRef(std::string method_ref) {
CHECK(is_client_);
method_ref_ = method_ref;
}
void SetData(std::string message_data) {
message_data_ = message_data;
CHECK_EQ((flags_ & kFlagMessageData), 0);
flags_ |= kFlagMessageData;
}
void SetSuffix(Metadata suffix_metadata) {
if (is_client_) CHECK(suffix_metadata.empty());
suffix_metadata_ = suffix_metadata;
CHECK_EQ((flags_ & kFlagSuffix), 0);
flags_ |= kFlagSuffix;
}
void SetStatusDescription(std::string status_desc) {
CHECK(!is_client_);
CHECK_EQ((flags_ & kFlagStatusDescription), 0);
status_desc_ = status_desc;
}
void SetStatus(int status) {
CHECK(!is_client_);
CHECK_EQ((flags_ >> 16), 0);
CHECK(status < (1 << 16));
flags_ |= (status << 16);
}
bool IsClient() const { return is_client_; }
bool IsServer() const { return !is_client_; }
int GetTxCode() const { return tx_code_; }
int GetFlags() const { return flags_; }
absl::string_view GetMethodRef() const { return method_ref_; }
const Metadata& GetPrefixMetadata() const { return prefix_metadata_; }
const Metadata& GetSuffixMetadata() const { return suffix_metadata_; }
absl::string_view GetMessageData() const { return message_data_; }
absl::string_view GetStatusDesc() const { return status_desc_; }
Transaction(const Transaction&) = delete;
void operator=(const Transaction&) = delete;
private:
int tx_code_;
bool is_client_;
Metadata prefix_metadata_;
Metadata suffix_metadata_;
std::string method_ref_;
std::string message_data_;
std::string status_desc_;
int flags_ = 0;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_TRANSACTION_H

@ -1,38 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_H
#include <grpc/support/port_platform.h>
#include <memory>
#include <utility>
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/util/orphanable.h"
namespace grpc_binder {
class WireReader : public grpc_core::InternallyRefCounted<WireReader> {
public:
~WireReader() override = default;
virtual std::shared_ptr<WireWriter> SetupTransport(
std::unique_ptr<Binder> endpoint_binder) = 0;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_H

@ -1,450 +0,0 @@
// 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/wire_format/wire_reader_impl.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <functional>
#include <limits>
#include <string>
#include <utility>
#include <vector>
#include "absl/functional/any_invocable.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/util/crash.h"
#include "src/core/util/status_helper.h"
namespace grpc_binder {
namespace {
const int32_t kWireFormatVersion = 1;
const char kAuthorityMetadataKey[] = ":authority";
absl::StatusOr<Metadata> parse_metadata(ReadableParcel* reader) {
int num_header;
GRPC_RETURN_IF_ERROR(reader->ReadInt32(&num_header));
if (num_header < 0) {
return absl::InvalidArgumentError("num_header cannot be negative");
}
std::vector<std::pair<std::string, std::string>> ret;
for (int i = 0; i < num_header; i++) {
int count;
GRPC_RETURN_IF_ERROR(reader->ReadInt32(&count));
std::string key{};
if (count > 0) GRPC_RETURN_IF_ERROR(reader->ReadByteArray(&key));
GRPC_RETURN_IF_ERROR(reader->ReadInt32(&count));
std::string value{};
if (count > 0) GRPC_RETURN_IF_ERROR(reader->ReadByteArray(&value));
ret.emplace_back(key, value);
}
return ret;
}
} // namespace
WireReaderImpl::WireReaderImpl(
std::shared_ptr<TransportStreamReceiver> transport_stream_receiver,
bool is_client,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy,
std::function<void()> on_destruct_callback)
: transport_stream_receiver_(std::move(transport_stream_receiver)),
is_client_(is_client),
security_policy_(security_policy),
on_destruct_callback_(on_destruct_callback) {}
WireReaderImpl::~WireReaderImpl() {
if (on_destruct_callback_) {
on_destruct_callback_();
}
}
std::shared_ptr<WireWriter> WireReaderImpl::SetupTransport(
std::unique_ptr<Binder> binder) {
if (!is_client_) {
connected_ = true;
SendSetupTransport(binder.get());
{
grpc_core::MutexLock lock(&mu_);
wire_writer_ = std::make_shared<WireWriterImpl>(std::move(binder));
}
wire_writer_ready_notification_.Notify();
return wire_writer_;
} else {
SendSetupTransport(binder.get());
auto other_end_binder = RecvSetupTransport();
{
grpc_core::MutexLock lock(&mu_);
connected_ = true;
wire_writer_ =
std::make_shared<WireWriterImpl>(std::move(other_end_binder));
}
wire_writer_ready_notification_.Notify();
return wire_writer_;
}
}
void WireReaderImpl::SendSetupTransport(Binder* binder) {
binder->Initialize();
const absl::Status prep_transaction_status = binder->PrepareTransaction();
VLOG(2) << "prepare transaction = " << prep_transaction_status;
WritableParcel* writable_parcel = binder->GetWritableParcel();
const absl::Status write_status =
writable_parcel->WriteInt32(kWireFormatVersion);
VLOG(2) << "write int32 = " << write_status;
// The lifetime of the transaction receiver is the same as the wire writer's.
// The transaction receiver is responsible for not calling the on-transact
// callback when it's dead.
// Give TransactionReceiver a Ref() since WireReader cannot be destructed
// during callback execution. TransactionReceiver should make sure that the
// callback owns a Ref() when it's being invoked.
tx_receiver_ = binder->ConstructTxReceiver(
/*wire_reader_ref=*/Ref(),
[this](transaction_code_t code, ReadableParcel* readable_parcel,
int uid) {
return this->ProcessTransaction(code, readable_parcel, uid);
});
VLOG(2) << "tx_receiver = " << tx_receiver_->GetRawBinder();
const absl::Status write_binder_status =
writable_parcel->WriteBinder(tx_receiver_.get());
VLOG(2) << "AParcel_writeStrongBinder = " << write_binder_status;
const absl::Status transact_status =
binder->Transact(BinderTransportTxCode::SETUP_TRANSPORT);
VLOG(2) << "AIBinder_transact = " << transact_status;
}
std::unique_ptr<Binder> WireReaderImpl::RecvSetupTransport() {
// TODO(b/191941760): avoid blocking, handle wire_writer_noti lifetime
// better
VLOG(2) << "start waiting for noti";
connection_noti_.WaitForNotification();
VLOG(2) << "end waiting for noti";
return std::move(other_end_binder_);
}
absl::Status WireReaderImpl::ProcessTransaction(transaction_code_t code,
ReadableParcel* parcel,
int uid) {
if (code >= static_cast<unsigned>(kFirstCallId)) {
return ProcessStreamingTransaction(code, parcel);
}
if (!(code >= static_cast<transaction_code_t>(
BinderTransportTxCode::SETUP_TRANSPORT) &&
code <= static_cast<transaction_code_t>(
BinderTransportTxCode::PING_RESPONSE))) {
LOG(INFO)
<< "Received unknown control message. Shutdown transport gracefully.";
// TODO(waynetu): Shutdown transport gracefully.
return absl::OkStatus();
}
{
grpc_core::MutexLock lock(&mu_);
if (static_cast<BinderTransportTxCode>(code) !=
BinderTransportTxCode::SETUP_TRANSPORT &&
!connected_) {
return absl::InvalidArgumentError("Transports not connected yet");
}
}
// TODO(mingcl): See if we want to check the security policy for every RPC
// call or just during transport setup.
switch (static_cast<BinderTransportTxCode>(code)) {
case BinderTransportTxCode::SETUP_TRANSPORT: {
grpc_core::MutexLock lock(&mu_);
if (recvd_setup_transport_) {
return absl::InvalidArgumentError(
"Already received a SETUP_TRANSPORT request");
}
recvd_setup_transport_ = true;
VLOG(2) << "calling uid = " << uid;
if (!security_policy_->IsAuthorized(uid)) {
return absl::PermissionDeniedError(
"UID " + std::to_string(uid) +
" is not allowed to connect to this "
"transport according to security policy.");
}
int version;
GRPC_RETURN_IF_ERROR(parcel->ReadInt32(&version));
VLOG(2) << "The other end respond with version = " << version;
// We only support this single lowest possible version, so server must
// respond that version too.
if (version != kWireFormatVersion) {
LOG(ERROR) << "The other end respond with version = " << version
<< ", but we requested version " << kWireFormatVersion
<< ", trying to continue anyway";
}
std::unique_ptr<Binder> binder{};
GRPC_RETURN_IF_ERROR(parcel->ReadBinder(&binder));
if (!binder) {
return absl::InternalError("Read NULL binder from the parcel");
}
binder->Initialize();
other_end_binder_ = std::move(binder);
connection_noti_.Notify();
break;
}
case BinderTransportTxCode::SHUTDOWN_TRANSPORT: {
LOG(ERROR)
<< "Received SHUTDOWN_TRANSPORT request but not implemented yet.";
return absl::UnimplementedError("SHUTDOWN_TRANSPORT");
}
case BinderTransportTxCode::ACKNOWLEDGE_BYTES: {
int64_t num_bytes = -1;
GRPC_RETURN_IF_ERROR(parcel->ReadInt64(&num_bytes));
VLOG(2) << "received acknowledge bytes = " << num_bytes;
if (!wire_writer_ready_notification_.WaitForNotificationWithTimeout(
absl::Seconds(5))) {
return absl::DeadlineExceededError(
"wire_writer_ is not ready in time!");
}
wire_writer_->OnAckReceived(num_bytes);
break;
}
case BinderTransportTxCode::PING: {
if (is_client_) {
return absl::FailedPreconditionError("Receive PING request in client");
}
int ping_id = -1;
GRPC_RETURN_IF_ERROR(parcel->ReadInt32(&ping_id));
VLOG(2) << "received ping id = " << ping_id;
// TODO(waynetu): Ping back.
break;
}
case BinderTransportTxCode::PING_RESPONSE: {
int value = -1;
GRPC_RETURN_IF_ERROR(parcel->ReadInt32(&value));
VLOG(2) << "received ping response = " << value;
break;
}
}
return absl::OkStatus();
}
absl::Status WireReaderImpl::ProcessStreamingTransaction(
transaction_code_t code, ReadableParcel* parcel) {
bool need_to_send_ack = false;
int64_t num_bytes = 0;
// Indicates which callbacks should be cancelled. It will be initialized as
// the flags the in-coming transaction carries, and when a particular
// callback is completed, the corresponding bit in cancellation_flag will be
// set to 0 so that we won't cancel it afterward.
int cancellation_flags = 0;
// The queue saves the actions needed to be done "WITHOUT" `mu_`.
// It prevents deadlock against wire writer issues.
std::queue<absl::AnyInvocable<void() &&>> deferred_func_queue;
absl::Status tx_process_result;
{
grpc_core::MutexLock lock(&mu_);
if (!connected_) {
return absl::InvalidArgumentError("Transports not connected yet");
}
tx_process_result = ProcessStreamingTransactionImpl(
code, parcel, &cancellation_flags, deferred_func_queue);
if ((num_incoming_bytes_ - num_acknowledged_bytes_) >=
kFlowControlAckBytes) {
need_to_send_ack = true;
num_bytes = num_incoming_bytes_;
num_acknowledged_bytes_ = num_incoming_bytes_;
}
}
// Executes all actions in the queue.
while (!deferred_func_queue.empty()) {
std::move(deferred_func_queue.front())();
deferred_func_queue.pop();
}
if (!tx_process_result.ok()) {
LOG(ERROR) << "Failed to process streaming transaction: "
<< tx_process_result.ToString();
// Something went wrong when receiving transaction. Cancel failed requests.
if (cancellation_flags & kFlagPrefix) {
LOG(INFO) << "cancelling initial metadata";
transport_stream_receiver_->NotifyRecvInitialMetadata(code,
tx_process_result);
}
if (cancellation_flags & kFlagMessageData) {
LOG(INFO) << "cancelling message data";
transport_stream_receiver_->NotifyRecvMessage(code, tx_process_result);
}
if (cancellation_flags & kFlagSuffix) {
LOG(INFO) << "cancelling trailing metadata";
transport_stream_receiver_->NotifyRecvTrailingMetadata(
code, tx_process_result, 0);
}
}
if (need_to_send_ack) {
if (!wire_writer_ready_notification_.WaitForNotificationWithTimeout(
absl::Seconds(5))) {
return absl::DeadlineExceededError("wire_writer_ is not ready in time!");
}
CHECK(wire_writer_);
// wire_writer_ should not be accessed while holding mu_!
// Otherwise, it is possible that
// 1. wire_writer_::mu_ is acquired before mu_ (NDK call back during
// transaction)
// 2. mu_ is acquired before wire_writer_::mu_ (e.g. Java call back us, and
// we call WireWriter::SendAck which will try to acquire wire_writer_::mu_)
absl::Status ack_status = wire_writer_->SendAck(num_bytes);
if (tx_process_result.ok()) {
return ack_status;
}
}
return tx_process_result;
}
absl::Status WireReaderImpl::ProcessStreamingTransactionImpl(
transaction_code_t code, ReadableParcel* parcel, int* cancellation_flags,
std::queue<absl::AnyInvocable<void() &&>>& deferred_func_queue) {
CHECK(cancellation_flags);
num_incoming_bytes_ += parcel->GetDataSize();
LOG(INFO) << "Total incoming bytes: " << num_incoming_bytes_;
int flags;
GRPC_RETURN_IF_ERROR(parcel->ReadInt32(&flags));
*cancellation_flags = flags;
// Ignore in-coming transaction with flag = 0 to match with Java
// implementation.
// TODO(waynetu): Check with grpc-java team to see whether this is the
// intended behavior.
// TODO(waynetu): What should be returned here?
if (flags == 0) {
LOG(INFO) << "[WARNING] Receive empty transaction. Ignored.";
return absl::OkStatus();
}
int status = flags >> 16;
VLOG(2) << "status = " << status;
VLOG(2) << "FLAG_PREFIX = " << (flags & kFlagPrefix);
VLOG(2) << "FLAG_MESSAGE_DATA = " << (flags & kFlagMessageData);
VLOG(2) << "FLAG_SUFFIX = " << (flags & kFlagSuffix);
int seq_num;
GRPC_RETURN_IF_ERROR(parcel->ReadInt32(&seq_num));
// TODO(waynetu): For now we'll just assume that the transactions commit in
// the same order they're issued. The following assertion detects
// out-of-order or missing transactions. WireReaderImpl should be fixed if
// we indeed found such behavior.
int32_t& expectation = expected_seq_num_[code];
if (seq_num < 0 || seq_num != expectation) {
// Unexpected sequence number.
return absl::InternalError("Unexpected sequence number");
}
// TODO(waynetu): According to the protocol, "The sequence number will wrap
// around to 0 if more than 2^31 messages are sent." For now we'll just
// assert that it never reach such circumstances.
CHECK(expectation < std::numeric_limits<int32_t>::max())
<< "Sequence number too large";
expectation++;
VLOG(2) << "sequence number = " << seq_num;
if (flags & kFlagPrefix) {
std::string method_ref;
if (!is_client_) {
GRPC_RETURN_IF_ERROR(parcel->ReadString(&method_ref));
}
absl::StatusOr<Metadata> initial_metadata_or_error = parse_metadata(parcel);
if (!initial_metadata_or_error.ok()) {
return initial_metadata_or_error.status();
}
if (!is_client_) {
// In BinderChannel wireformat specification, path is not encoded as part
// of metadata. So we extract the path and turn it into metadata here
// (this is what core API layer expects).
initial_metadata_or_error->emplace_back(":path",
std::string("/") + method_ref);
// Since authority metadata is not part of BinderChannel wireformat
// specification, and gRPC core API layer expects the presence of
// authority for message sent from client to server, we add one if
// missing (it will be missing if client grpc-java).
bool has_authority = false;
for (const auto& p : *initial_metadata_or_error) {
if (p.first == kAuthorityMetadataKey) has_authority = true;
}
if (!has_authority) {
initial_metadata_or_error->emplace_back(kAuthorityMetadataKey,
"binder.authority");
}
}
deferred_func_queue.emplace([this, code,
initial_metadata_or_error = std::move(
initial_metadata_or_error)]() mutable {
this->transport_stream_receiver_->NotifyRecvInitialMetadata(
code, std::move(initial_metadata_or_error));
});
*cancellation_flags &= ~kFlagPrefix;
}
if (flags & kFlagMessageData) {
int count;
GRPC_RETURN_IF_ERROR(parcel->ReadInt32(&count));
VLOG(2) << "count = " << count;
std::string msg_data{};
if (count > 0) {
GRPC_RETURN_IF_ERROR(parcel->ReadByteArray(&msg_data));
}
message_buffer_[code] += msg_data;
if ((flags & kFlagMessageDataIsPartial) == 0) {
std::string s = std::move(message_buffer_[code]);
message_buffer_.erase(code);
deferred_func_queue.emplace([this, code, s = std::move(s)]() mutable {
this->transport_stream_receiver_->NotifyRecvMessage(code, std::move(s));
});
}
*cancellation_flags &= ~kFlagMessageData;
}
if (flags & kFlagSuffix) {
if (flags & kFlagStatusDescription) {
// FLAG_STATUS_DESCRIPTION set
std::string desc;
GRPC_RETURN_IF_ERROR(parcel->ReadString(&desc));
VLOG(2) << "description = " << desc;
}
Metadata trailing_metadata;
if (is_client_) {
absl::StatusOr<Metadata> trailing_metadata_or_error =
parse_metadata(parcel);
if (!trailing_metadata_or_error.ok()) {
return trailing_metadata_or_error.status();
}
trailing_metadata = *trailing_metadata_or_error;
}
deferred_func_queue.emplace(
[this, code, trailing_metadata = std::move(trailing_metadata),
status]() mutable {
this->transport_stream_receiver_->NotifyRecvTrailingMetadata(
code, std::move(trailing_metadata), status);
});
*cancellation_flags &= ~kFlagSuffix;
}
return absl::OkStatus();
}
} // namespace grpc_binder
#endif

@ -1,158 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_IMPL_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_IMPL_H
#include <grpc/support/port_platform.h>
#include <grpcpp/security/binder_security_policy.h>
#include <memory>
#include <queue>
#include <utility>
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
#include "src/core/util/notification.h"
namespace grpc_binder {
class WireReaderImpl : public WireReader {
public:
WireReaderImpl(
std::shared_ptr<TransportStreamReceiver> transport_stream_receiver,
bool is_client,
std::shared_ptr<grpc::experimental::binder::SecurityPolicy>
security_policy,
std::function<void()> on_destruct_callback = nullptr);
~WireReaderImpl() override;
void Orphan() override { Unref(); }
/// Setup the transport between endpoint binders.
///
/// The client and the server both call SetupTransport() when constructing
/// transport.
///
/// High-level overview of transaction setup:
/// 0. Client obtains an |endpoint_binder| from the server (in the Android
/// setting, this can be achieved by "binding" to the server APK).
/// 1. Client creates a binder |client_binder| and hook its on-transaction
/// callback to client's ProcessTransaction(). Client then sends
/// |client_binder| through |endpoint_binder| to server.
/// 2. Server receives |client_binder| via |endpoint_binder|.
/// 3. Server creates a binder |server_binder| and hook its on-transaction
/// callback to server's ProcessTransaction(). Server then sends
/// |server_binder| through |client_binder| back to the client.
/// 4. Client receives |server_binder| via |client_binder|'s on-transaction
/// callback.
///
/// The parameter \p binder here means different things for client nad server.
/// For client, \p binder refers to |endpoint_binder|, and for server, \p
/// binder refers to |client_binder|. That is, for server-side transport
/// setup, we assume that the first half of SETUP_TRANSPORT (up to step 2) is
/// already done somewhere else (see test/end2end/binder_transport_test.cc for
/// how it's handled in the testing environment).
std::shared_ptr<WireWriter> SetupTransport(
std::unique_ptr<Binder> binder) override;
absl::Status ProcessTransaction(transaction_code_t code,
ReadableParcel* parcel, int uid);
/// Send SETUP_TRANSPORT request through \p binder.
///
/// This is the one half (for client it's the first half, and for server it's
/// the second) of the SETUP_TRANSPORT negotiation process. First, a new
/// binder is created. We take its "receiving" part and construct the
/// transaction receiver with it, and sends the "sending" part along with the
/// SETUP_TRANSPORT message through \p binder.
void SendSetupTransport(Binder* binder);
/// Recv SETUP_TRANSPORT request.
///
/// This is the other half of the SETUP_TRANSPORT process. We wait for
/// in-coming SETUP_TRANSPORT request with the "sending" part of a binder from
/// the other end. For client, the message is coming from the transaction
/// receiver we just constructed in SendSetupTransport(). For server, we
/// assume that this step is already completed.
// TODO(waynetu): In the testing environment, we still use this method (on
// another WireReader instance) for server-side transport setup, and thus it
// is marked as public. Try moving this method back to private, and hopefully
// we can also avoid moving |other_end_binder_| out in the implementation.
std::unique_ptr<Binder> RecvSetupTransport();
private:
absl::Status ProcessStreamingTransaction(transaction_code_t code,
ReadableParcel* parcel);
absl::Status ProcessStreamingTransactionImpl(
transaction_code_t code, ReadableParcel* parcel, int* cancellation_flags,
// The queue saves the actions needed to be done "WITHOUT" `mu_`.
// It prevents deadlock against wire writer issues.
std::queue<absl::AnyInvocable<void() &&>>& deferred_func_queue)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
std::shared_ptr<TransportStreamReceiver> transport_stream_receiver_;
grpc_core::Notification connection_noti_;
grpc_core::Mutex mu_;
std::atomic_bool connected_{false};
bool recvd_setup_transport_ ABSL_GUARDED_BY(mu_) = false;
// NOTE: other_end_binder_ will be moved out when RecvSetupTransport() is
// called. Be cautious not to access it afterward.
std::unique_ptr<Binder> other_end_binder_;
absl::flat_hash_map<transaction_code_t, int32_t> expected_seq_num_
ABSL_GUARDED_BY(mu_);
absl::flat_hash_map<transaction_code_t, std::string> message_buffer_
ABSL_GUARDED_BY(mu_);
std::unique_ptr<TransactionReceiver> tx_receiver_;
bool is_client_;
std::shared_ptr<grpc::experimental::binder::SecurityPolicy> security_policy_;
// When WireReaderImpl gets destructed, call on_destruct_callback_. This is
// mostly for decrementing the reference count of its transport.
std::function<void()> on_destruct_callback_;
// ACK every 16k bytes.
static constexpr int64_t kFlowControlAckBytes = 16 * 1024;
int64_t num_incoming_bytes_ ABSL_GUARDED_BY(mu_) = 0;
int64_t num_acknowledged_bytes_ ABSL_GUARDED_BY(mu_) = 0;
// Used to send ACK.
std::shared_ptr<WireWriter> wire_writer_;
// Workaround for race condition.
//
// In `SetupTransport()`, we set `connected_` to true, call
// `SendSetupTransport()`, and construct `wire_writer_`. There is a potential
// race condition between calling `SendSetupTransport()` and constructing
// `wire_writer_`. So use this notification to wait. This should be very fast
// and waiting is acceptable.
//
// The original problem was that we can't move `connected_ = true` and
// `SendSetupTransport()` into the mutex, as it will deadlock if
// `ProcessTransaction()` is called in the same call chain.
//
// Note: this is not the perfect solution, the system will still deadlock if,
// e.g., the first request is 64K and we entered the sending ACK code path.
//
// TODO(littlecvr): Figure out a better solution to not causing any potential
// deadlock and not having to wait.
grpc_core::Notification wire_writer_ready_notification_;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_READER_IMPL_H

@ -1,393 +0,0 @@
// 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/wire_format/wire_writer.h"
#include <grpc/support/port_platform.h>
#ifndef GRPC_NO_BINDER
#include <utility>
#include "absl/cleanup/cleanup.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/types/variant.h"
#include "src/core/lib/event_engine/default_event_engine.h"
#include "src/core/util/crash.h"
#define RETURN_IF_ERROR(expr) \
do { \
const absl::Status status = (expr); \
if (!status.ok()) return status; \
} while (0)
namespace grpc_binder {
bool CanBeSentInOneTransaction(const Transaction& tx) {
return (tx.GetFlags() & kFlagMessageData) == 0 ||
static_cast<int64_t>(tx.GetMessageData().size()) <=
WireWriterImpl::kBlockSize;
}
// Simply forward the call to `WireWriterImpl::RunScheduledTx`.
void RunScheduledTx(void* arg, grpc_error_handle /*error*/) {
auto* run_scheduled_tx_args =
static_cast<WireWriterImpl::RunScheduledTxArgs*>(arg);
run_scheduled_tx_args->writer->RunScheduledTxInternal(run_scheduled_tx_args);
}
absl::Status WriteInitialMetadata(const Transaction& tx,
WritableParcel* parcel) {
if (tx.IsClient()) {
// Only client sends method ref.
RETURN_IF_ERROR(parcel->WriteString(tx.GetMethodRef()));
}
RETURN_IF_ERROR(parcel->WriteInt32(tx.GetPrefixMetadata().size()));
for (const auto& md : tx.GetPrefixMetadata()) {
RETURN_IF_ERROR(parcel->WriteByteArrayWithLength(md.first));
RETURN_IF_ERROR(parcel->WriteByteArrayWithLength(md.second));
}
return absl::OkStatus();
}
absl::Status WriteTrailingMetadata(const Transaction& tx,
WritableParcel* parcel) {
if (tx.IsServer()) {
if (tx.GetFlags() & kFlagStatusDescription) {
RETURN_IF_ERROR(parcel->WriteString(tx.GetStatusDesc()));
}
RETURN_IF_ERROR(parcel->WriteInt32(tx.GetSuffixMetadata().size()));
for (const auto& md : tx.GetSuffixMetadata()) {
RETURN_IF_ERROR(parcel->WriteByteArrayWithLength(md.first));
RETURN_IF_ERROR(parcel->WriteByteArrayWithLength(md.second));
}
} else {
// client suffix currently is always empty according to the wireformat
if (!tx.GetSuffixMetadata().empty()) {
LOG(ERROR) << "Got non-empty suffix metadata from client.";
}
}
return absl::OkStatus();
}
WireWriterImpl::WireWriterImpl(std::unique_ptr<Binder> binder)
: binder_(std::move(binder)),
combiner_(grpc_combiner_create(
grpc_event_engine::experimental::GetDefaultEventEngine())) {}
WireWriterImpl::~WireWriterImpl() {
GRPC_COMBINER_UNREF(combiner_, "wire_writer_impl");
while (!pending_outgoing_tx_.empty()) {
delete pending_outgoing_tx_.front();
pending_outgoing_tx_.pop();
}
}
// Flow control constant are specified at
// https://github.com/grpc/proposal/blob/master/L73-java-binderchannel/wireformat.md#flow-control
const int64_t WireWriterImpl::kBlockSize = 16 * 1024;
const int64_t WireWriterImpl::kFlowControlWindowSize = 128 * 1024;
absl::Status WireWriterImpl::MakeBinderTransaction(
BinderTransportTxCode tx_code,
std::function<absl::Status(WritableParcel*)> fill_parcel) {
grpc_core::MutexLock lock(&write_mu_);
RETURN_IF_ERROR(binder_->PrepareTransaction());
WritableParcel* parcel = binder_->GetWritableParcel();
RETURN_IF_ERROR(fill_parcel(parcel));
// Only stream transaction is accounted in flow control spec.
if (static_cast<int32_t>(tx_code) >= kFirstCallId) {
int64_t parcel_size = parcel->GetDataSize();
if (parcel_size > 2 * kBlockSize) {
LOG(ERROR) << "Unexpected large transaction (possibly caused by a very "
"large metadata). This might overflow the binder "
"transaction buffer. Size: "
<< parcel_size << " bytes";
}
num_outgoing_bytes_ += parcel_size;
LOG(INFO) << "Total outgoing bytes: " << num_outgoing_bytes_.load();
}
CHECK(!is_transacting_);
is_transacting_ = true;
absl::Status result = binder_->Transact(tx_code);
is_transacting_ = false;
return result;
}
absl::Status WireWriterImpl::RpcCallFastPath(std::unique_ptr<Transaction> tx) {
return MakeBinderTransaction(
static_cast<BinderTransportTxCode>(tx->GetTxCode()),
[this, tx = tx.get()](
WritableParcel* parcel) ABSL_EXCLUSIVE_LOCKS_REQUIRED(write_mu_) {
RETURN_IF_ERROR(parcel->WriteInt32(tx->GetFlags()));
RETURN_IF_ERROR(parcel->WriteInt32(next_seq_num_[tx->GetTxCode()]++));
if (tx->GetFlags() & kFlagPrefix) {
RETURN_IF_ERROR(WriteInitialMetadata(*tx, parcel));
}
if (tx->GetFlags() & kFlagMessageData) {
RETURN_IF_ERROR(
parcel->WriteByteArrayWithLength(tx->GetMessageData()));
}
if (tx->GetFlags() & kFlagSuffix) {
RETURN_IF_ERROR(WriteTrailingMetadata(*tx, parcel));
}
return absl::OkStatus();
});
}
absl::Status WireWriterImpl::RunStreamTx(
RunScheduledTxArgs::StreamTx* stream_tx, WritableParcel* parcel,
bool* is_last_chunk) {
Transaction* tx = stream_tx->tx.get();
// Transaction without data flag should go to fast path.
CHECK(tx->GetFlags() & kFlagMessageData);
absl::string_view data = tx->GetMessageData();
CHECK(stream_tx->bytes_sent <= static_cast<int64_t>(data.size()));
int flags = kFlagMessageData;
if (stream_tx->bytes_sent == 0) {
// This is the first transaction. Include initial
// metadata if there's any.
if (tx->GetFlags() & kFlagPrefix) {
flags |= kFlagPrefix;
}
}
// There is also prefix/suffix in transaction beside the transaction data so
// actual transaction size will be greater than `kBlockSize`. This is
// unavoidable because we cannot split the prefix metadata and trailing
// metadata into different binder transactions. In most cases this is fine
// because single transaction size is not required to be strictly lower than
// `kBlockSize`, as long as it won't overflow Android's binder buffer.
int64_t size = std::min<int64_t>(WireWriterImpl::kBlockSize,
data.size() - stream_tx->bytes_sent);
if (stream_tx->bytes_sent + WireWriterImpl::kBlockSize >=
static_cast<int64_t>(data.size())) {
// This is the last transaction. Include trailing
// metadata if there's any.
if (tx->GetFlags() & kFlagSuffix) {
flags |= kFlagSuffix;
}
size = data.size() - stream_tx->bytes_sent;
*is_last_chunk = true;
} else {
// There are more messages to send.
flags |= kFlagMessageDataIsPartial;
*is_last_chunk = false;
}
RETURN_IF_ERROR(parcel->WriteInt32(flags));
RETURN_IF_ERROR(parcel->WriteInt32(next_seq_num_[tx->GetTxCode()]++));
if (flags & kFlagPrefix) {
RETURN_IF_ERROR(WriteInitialMetadata(*tx, parcel));
}
RETURN_IF_ERROR(parcel->WriteByteArrayWithLength(
data.substr(stream_tx->bytes_sent, size)));
if (flags & kFlagSuffix) {
RETURN_IF_ERROR(WriteTrailingMetadata(*tx, parcel));
}
stream_tx->bytes_sent += size;
return absl::OkStatus();
}
void WireWriterImpl::RunScheduledTxInternal(RunScheduledTxArgs* args) {
CHECK(args->writer == this);
if (absl::holds_alternative<RunScheduledTxArgs::AckTx>(args->tx)) {
int64_t num_bytes =
absl::get<RunScheduledTxArgs::AckTx>(args->tx).num_bytes;
absl::Status result =
MakeBinderTransaction(BinderTransportTxCode::ACKNOWLEDGE_BYTES,
[num_bytes](WritableParcel* parcel) {
RETURN_IF_ERROR(parcel->WriteInt64(num_bytes));
return absl::OkStatus();
});
if (!result.ok()) {
LOG(ERROR) << "Failed to make binder transaction " << result;
}
delete args;
return;
}
CHECK(absl::holds_alternative<RunScheduledTxArgs::StreamTx>(args->tx));
RunScheduledTxArgs::StreamTx* stream_tx =
&absl::get<RunScheduledTxArgs::StreamTx>(args->tx);
// Be reservative. Decrease CombinerTxCount after the data size of this
// transaction has already been added to `num_outgoing_bytes_`, to make sure
// we never underestimate `num_outgoing_bytes_`.
auto decrease_combiner_tx_count = absl::MakeCleanup([this]() {
{
grpc_core::MutexLock lock(&flow_control_mu_);
CHECK_GT(num_non_acked_tx_in_combiner_, 0);
num_non_acked_tx_in_combiner_--;
}
// New transaction might be ready to be scheduled.
TryScheduleTransaction();
});
if (CanBeSentInOneTransaction(*stream_tx->tx.get())) { // NOLINT
absl::Status result = RpcCallFastPath(std::move(stream_tx->tx));
if (!result.ok()) {
LOG(ERROR) << "Failed to handle non-chunked RPC call " << result;
}
delete args;
return;
}
bool is_last_chunk = true;
absl::Status result = MakeBinderTransaction(
static_cast<BinderTransportTxCode>(stream_tx->tx->GetTxCode()),
[stream_tx, &is_last_chunk, this](WritableParcel* parcel)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(write_mu_) {
return RunStreamTx(stream_tx, parcel, &is_last_chunk);
});
if (!result.ok()) {
LOG(ERROR) << "Failed to make binder transaction " << result;
}
if (!is_last_chunk) {
{
grpc_core::MutexLock lock(&flow_control_mu_);
pending_outgoing_tx_.push(args);
}
TryScheduleTransaction();
} else {
delete args;
}
}
absl::Status WireWriterImpl::RpcCall(std::unique_ptr<Transaction> tx) {
// TODO(mingcl): check tx_code <= last call id
CHECK(tx->GetTxCode() >= kFirstCallId);
auto args = new RunScheduledTxArgs();
args->writer = this;
args->tx = RunScheduledTxArgs::StreamTx();
absl::get<RunScheduledTxArgs::StreamTx>(args->tx).tx = std::move(tx);
absl::get<RunScheduledTxArgs::StreamTx>(args->tx).bytes_sent = 0;
{
grpc_core::MutexLock lock(&flow_control_mu_);
pending_outgoing_tx_.push(args);
}
TryScheduleTransaction();
return absl::OkStatus();
}
absl::Status WireWriterImpl::SendAck(int64_t num_bytes) {
// Ensure combiner will be run if this is not called from top-level gRPC API
// entrypoint.
grpc_core::ExecCtx exec_ctx;
LOG(INFO) << "Ack " << num_bytes << " bytes received";
if (is_transacting_) {
// This can happen because NDK might call our registered callback function
// in the same thread while we are telling it to send a transaction
// `is_transacting_` will be true. `Binder::Transact` is now being called on
// the same thread or the other thread. We are currently in the call stack
// of other transaction, Liveness of ACK is still guaranteed even if this is
// a race with another thread.
LOG(INFO) << "Scheduling ACK transaction instead of directly execute it to "
"avoid deadlock.";
auto args = new RunScheduledTxArgs();
args->writer = this;
args->tx = RunScheduledTxArgs::AckTx();
absl::get<RunScheduledTxArgs::AckTx>(args->tx).num_bytes = num_bytes;
auto cl = GRPC_CLOSURE_CREATE(RunScheduledTx, args, nullptr);
combiner_->Run(cl, absl::OkStatus());
return absl::OkStatus();
}
// Otherwise, we can directly send ack.
absl::Status result =
MakeBinderTransaction((BinderTransportTxCode::ACKNOWLEDGE_BYTES),
[num_bytes](WritableParcel* parcel) {
RETURN_IF_ERROR(parcel->WriteInt64(num_bytes));
return absl::OkStatus();
});
if (!result.ok()) {
LOG(ERROR) << "Failed to make binder transaction " << result;
}
return result;
}
void WireWriterImpl::OnAckReceived(int64_t num_bytes) {
// Ensure combiner will be run if this is not called from top-level gRPC API
// entrypoint.
grpc_core::ExecCtx exec_ctx;
LOG(INFO) << "OnAckReceived " << num_bytes;
// Do not try to obtain `write_mu_` in this function. NDKBinder might invoke
// the callback to notify us about new incoming binder transaction when we are
// sending transaction. i.e. `write_mu_` might have already been acquired by
// this thread.
{
grpc_core::MutexLock lock(&flow_control_mu_);
num_acknowledged_bytes_ = std::max(num_acknowledged_bytes_, num_bytes);
int64_t num_outgoing_bytes = num_outgoing_bytes_;
if (num_acknowledged_bytes_ > num_outgoing_bytes) {
LOG(ERROR) << "The other end of transport acked more bytes than we ever "
"sent, "
<< num_acknowledged_bytes_ << " > " << num_outgoing_bytes;
}
}
TryScheduleTransaction();
}
void WireWriterImpl::TryScheduleTransaction() {
while (true) {
grpc_core::MutexLock lock(&flow_control_mu_);
if (pending_outgoing_tx_.empty()) {
// Nothing to be schduled.
break;
}
// Number of bytes we have scheduled in combiner but have not yet be
// executed by combiner. Here we make an assumption that every binder
// transaction will take `kBlockSize`. This should be close to truth when a
// large message is being cut to `kBlockSize` chunks.
int64_t num_bytes_scheduled_in_combiner =
num_non_acked_tx_in_combiner_ * kBlockSize;
// An estimation of number of bytes of traffic we will eventually send to
// the other end, assuming all tasks in combiner will be executed and we
// receive no new ACK from the other end of transport.
int64_t num_total_bytes_will_be_sent =
num_outgoing_bytes_ + num_bytes_scheduled_in_combiner;
// An estimation of number of bytes of traffic that will not be
// acknowledged, assuming all tasks in combiner will be executed and we
// receive no new ack message fomr the other end of transport.
int64_t num_non_acked_bytes_estimation =
num_total_bytes_will_be_sent - num_acknowledged_bytes_;
if (num_non_acked_bytes_estimation < 0) {
LOG(ERROR) << "Something went wrong. `num_non_acked_bytes_estimation` "
"should be non-negative but it is "
<< num_non_acked_bytes_estimation;
}
// If we can schedule another transaction (which has size estimation of
// `kBlockSize`) without exceeding `kFlowControlWindowSize`, schedule it.
if ((num_non_acked_bytes_estimation + kBlockSize <
kFlowControlWindowSize)) {
num_non_acked_tx_in_combiner_++;
combiner_->Run(GRPC_CLOSURE_CREATE(RunScheduledTx,
pending_outgoing_tx_.front(), nullptr),
absl::OkStatus());
pending_outgoing_tx_.pop();
} else {
// It is common to fill `kFlowControlWindowSize` completely because
// transactions are send at faster rate than the other end of transport
// can handle it, so here we use VLOG(2).
VLOG(2) << "Some work cannot be scheduled yet due to slow ack from the "
"other end of transport. This transport might be blocked if "
"this number don't go down. pending_outgoing_tx_.size() = "
<< pending_outgoing_tx_.size()
<< " pending_outgoing_tx_.front() = "
<< pending_outgoing_tx_.front();
break;
}
}
}
} // namespace grpc_binder
#endif

@ -1,126 +0,0 @@
// 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_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_WRITER_H
#define GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_WRITER_H
#include <grpc/support/port_platform.h>
#include <queue>
#include <string>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/transaction.h"
#include "src/core/lib/iomgr/combiner.h"
#include "src/core/util/sync.h"
namespace grpc_binder {
// Member functions are thread safe.
class WireWriter {
public:
virtual ~WireWriter() = default;
virtual absl::Status RpcCall(std::unique_ptr<Transaction> tx) = 0;
virtual absl::Status SendAck(int64_t num_bytes) = 0;
virtual void OnAckReceived(int64_t num_bytes) = 0;
};
class WireWriterImpl : public WireWriter {
public:
explicit WireWriterImpl(std::unique_ptr<Binder> binder);
~WireWriterImpl() override;
absl::Status RpcCall(std::unique_ptr<Transaction> tx) override;
absl::Status SendAck(int64_t num_bytes) override;
void OnAckReceived(int64_t num_bytes) override;
// Required to be public because we would like to call this in combiner (which
// cannot invoke class member function). `RunScheduledTxArgs` and
// `RunScheduledTxInternal` should not be used by user directly.
struct RunScheduledTxArgs {
WireWriterImpl* writer;
struct StreamTx {
std::unique_ptr<Transaction> tx;
// How many data in transaction's `data` field has been sent.
int64_t bytes_sent = 0;
};
struct AckTx {
int64_t num_bytes;
};
absl::variant<AckTx, StreamTx> tx;
};
void RunScheduledTxInternal(RunScheduledTxArgs* arg);
// Split long message into chunks of size 16k. This doesn't necessarily have
// to be the same as the flow control acknowledgement size, but it should not
// exceed 128k.
static const int64_t kBlockSize;
// Flow control allows sending at most 128k between acknowledgements.
static const int64_t kFlowControlWindowSize;
private:
// Fast path: send data in one transaction.
absl::Status RpcCallFastPath(std::unique_ptr<Transaction> tx);
// This function will acquire `write_mu_` to make sure the binder is not used
// concurrently, so this can be called by different threads safely.
absl::Status MakeBinderTransaction(
BinderTransportTxCode tx_code,
std::function<absl::Status(WritableParcel*)> fill_parcel);
// Send a stream to `binder_`. Set `is_last_chunk` to `true` if the stream
// transaction has been sent completely. Otherwise set to `false`.
absl::Status RunStreamTx(RunScheduledTxArgs::StreamTx* stream_tx,
WritableParcel* parcel, bool* is_last_chunk)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(write_mu_);
// Schdule `RunScheduledTxArgs*` in `pending_outgoing_tx_` to `combiner_`, as
// many as possible (under the constraint of `kFlowControlWindowSize`).
void TryScheduleTransaction();
// Guards variables related to transport state.
grpc_core::Mutex write_mu_;
std::unique_ptr<Binder> binder_ ABSL_GUARDED_BY(write_mu_);
// Maps the transaction code (which identifies streams) to their next
// available sequence number. See
// https://github.com/grpc/proposal/blob/master/L73-java-binderchannel/wireformat.md#sequence-number
absl::flat_hash_map<int, int> next_seq_num_ ABSL_GUARDED_BY(write_mu_);
// Number of bytes we have already sent in stream transactions.
std::atomic<int64_t> num_outgoing_bytes_{0};
// Guards variables related to flow control logic.
grpc_core::Mutex flow_control_mu_;
int64_t num_acknowledged_bytes_ ABSL_GUARDED_BY(flow_control_mu_) = 0;
// The queue takes ownership of the pointer.
std::queue<RunScheduledTxArgs*> pending_outgoing_tx_
ABSL_GUARDED_BY(flow_control_mu_);
int num_non_acked_tx_in_combiner_ ABSL_GUARDED_BY(flow_control_mu_) = 0;
// Helper variable for determining if we are currently calling into
// `Binder::Transact`. Useful for avoiding the attempt of acquiring
// `write_mu_` multiple times on the same thread.
std::atomic_bool is_transacting_{false};
grpc_core::Combiner* combiner_;
};
} // namespace grpc_binder
#endif // GRPC_SRC_CORE_EXT_TRANSPORT_BINDER_WIRE_FORMAT_WIRE_WRITER_H

@ -72,9 +72,6 @@ extern void RegisterLoadBalancedCallDestination(
#ifndef GRPC_NO_RLS
extern void RegisterRlsLbPolicy(CoreConfiguration::Builder* builder);
#endif // !GRPC_NO_RLS
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
extern void RegisterBinderResolver(CoreConfiguration::Builder* builder);
#endif
namespace {
@ -122,9 +119,6 @@ void BuildCoreConfiguration(CoreConfiguration::Builder* builder) {
RegisterFakeResolver(builder);
RegisterHttpProxyMapper(builder);
RegisterLoadBalancedCallDestination(builder);
#ifdef GPR_SUPPORT_BINDER_TRANSPORT
RegisterBinderResolver(builder);
#endif
#ifndef GRPC_NO_RLS
RegisterRlsLbPolicy(builder);
#endif // !GRPC_NO_RLS

@ -1,9 +0,0 @@
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.

@ -1,151 +0,0 @@
// 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 <grpc/support/port_platform.h>
#include <algorithm>
#include "absl/status/status.h"
#include "src/core/lib/iomgr/port.h" // IWYU pragma: keep
#include "src/core/util/status_helper.h"
#ifdef GRPC_HAVE_UNIX_SOCKET
#include <string.h>
#ifdef GPR_WINDOWS
// clang-format off
#include <ws2def.h>
#include <afunix.h>
// clang-format on
#else
#include <sys/socket.h>
#include <sys/un.h>
#endif // GPR_WINDOWS
#include <memory>
#include <utility>
#include "absl/log/log.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/resolved_address.h"
#include "src/core/resolver/endpoint_addresses.h"
#include "src/core/resolver/resolver.h"
#include "src/core/resolver/resolver_factory.h"
#include "src/core/util/orphanable.h"
#include "src/core/util/uri.h"
namespace grpc_core {
namespace {
class BinderResolver final : public Resolver {
public:
BinderResolver(EndpointAddressesList addresses, ResolverArgs args)
: result_handler_(std::move(args.result_handler)),
addresses_(std::move(addresses)),
channel_args_(std::move(args.args)) {}
void StartLocked() override {
Result result;
result.addresses = std::move(addresses_);
result.args = channel_args_;
channel_args_ = ChannelArgs();
result_handler_->ReportResult(std::move(result));
}
void ShutdownLocked() override {}
private:
std::unique_ptr<ResultHandler> result_handler_;
EndpointAddressesList addresses_;
ChannelArgs channel_args_;
};
class BinderResolverFactory final : public ResolverFactory {
public:
absl::string_view scheme() const override { return "binder"; }
bool IsValidUri(const URI& uri) const override {
return ParseUri(uri, nullptr);
}
OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
EndpointAddressesList addresses;
if (!ParseUri(args.uri, &addresses)) return nullptr;
return MakeOrphanable<BinderResolver>(std::move(addresses),
std::move(args));
}
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("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<struct sockaddr_un*>(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(
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<socklen_t>(sizeof(un->sun_family) + path.size() + 1);
return absl::OkStatus();
}
static bool ParseUri(const URI& uri, EndpointAddressesList* addresses) {
grpc_resolved_address addr;
{
if (!uri.authority().empty()) {
LOG(ERROR) << "authority is not supported in binder scheme";
return false;
}
grpc_error_handle error = BinderAddrPopulate(uri.path(), &addr);
if (!error.ok()) {
LOG(ERROR) << StatusToString(error);
return false;
}
}
if (addresses != nullptr) {
addresses->emplace_back(addr, ChannelArgs());
}
return true;
}
};
} // namespace
void RegisterBinderResolver(CoreConfiguration::Builder* builder) {
builder->resolver_registry()->RegisterResolverFactory(
std::make_unique<BinderResolverFactory>());
}
} // namespace grpc_core
#endif

@ -707,7 +707,6 @@ CORE_SOURCE_FILES = [
'src/core/load_balancing/xds/xds_wrr_locality.cc',
'src/core/plugin_registry/grpc_plugin_registry.cc',
'src/core/plugin_registry/grpc_plugin_registry_extra.cc',
'src/core/resolver/binder/binder_resolver.cc',
'src/core/resolver/dns/c_ares/dns_resolver_ares.cc',
'src/core/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc',
'src/core/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc',

@ -36,22 +36,6 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "binder_resolver_test",
srcs = ["binder_resolver_test.cc"],
external_deps = [
"absl/log:log",
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//src/core:grpc_resolver_binder",
"//test/core/test_util:grpc_test_util",
],
)
grpc_cc_test(
name = "dns_resolver_test",
srcs = ["dns_resolver_test.cc"],

@ -1,216 +0,0 @@
// 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 <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "gtest/gtest.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/iomgr/port.h"
#include "src/core/lib/iomgr/resolved_address.h"
#include "src/core/resolver/endpoint_addresses.h"
#include "src/core/resolver/resolver.h"
#include "src/core/resolver/resolver_factory.h"
#include "src/core/util/orphanable.h"
#include "src/core/util/uri.h"
#include "test/core/test_util/test_config.h"
#ifdef GRPC_HAVE_UNIX_SOCKET
#ifdef GPR_WINDOWS
// clang-format off
#include <ws2def.h>
#include <afunix.h>
// clang-format on
#else
#include <sys/socket.h>
#include <sys/un.h>
#endif // GPR_WINDOWS
#include <grpc/grpc.h>
#include "absl/log/log.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/resolver/resolver_registry.h"
// Registers the factory with `grpc_core::ResolverRegistry`. Defined in
// binder_resolver.cc
namespace grpc_core {
void RegisterBinderResolver(CoreConfiguration::Builder* builder);
}
namespace {
class BinderResolverTest : public ::testing::Test {
public:
BinderResolverTest() {
factory_ = grpc_core::CoreConfiguration::Get()
.resolver_registry()
.LookupResolverFactory("binder");
}
~BinderResolverTest() override {}
static void SetUpTestSuite() {
builder_ =
std::make_unique<grpc_core::CoreConfiguration::WithSubstituteBuilder>(
[](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::CoreConfiguration::Get()
.resolver_registry()
.LookupResolverFactory("binder") == nullptr) {
}
}
static void TearDownTestSuite() {
grpc_shutdown();
builder_.reset();
}
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 ReportResult(grpc_core::Resolver::Result result) override {
EXPECT_TRUE(expect_result_);
ASSERT_TRUE(result.addresses.ok());
ASSERT_EQ(result.addresses->size(), 1);
grpc_core::EndpointAddresses addr = (*result.addresses)[0];
const struct sockaddr_un* un =
reinterpret_cast<const struct sockaddr_un*>(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_);
}
private:
// Whether we expect ReportResult function to be invoked
bool expect_result_ = false;
std::string expected_binder_id_;
};
void TestSucceeds(const char* string, const std::string& expected_path) {
VLOG(2) << "test: '" << string << "' should be valid for '"
<< factory_->scheme();
grpc_core::ExecCtx exec_ctx;
absl::StatusOr<grpc_core::URI> 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 =
std::make_unique<BinderResolverTest::ResultHandler>(expected_path);
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory_->CreateResolver(std::move(args));
ASSERT_TRUE(resolver != nullptr);
resolver->StartLocked();
}
void TestFails(const char* string) {
VLOG(2) << "test: '" << string << "' should be invalid for '"
<< factory_->scheme();
grpc_core::ExecCtx exec_ctx;
absl::StatusOr<grpc_core::URI> 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 = std::make_unique<BinderResolverTest::ResultHandler>();
grpc_core::OrphanablePtr<grpc_core::Resolver> resolver =
factory_->CreateResolver(std::move(args));
EXPECT_TRUE(resolver == nullptr);
}
private:
grpc_core::ResolverFactory* factory_;
static std::unique_ptr<grpc_core::CoreConfiguration::WithSubstituteBuilder>
builder_;
};
std::unique_ptr<grpc_core::CoreConfiguration::WithSubstituteBuilder>
BinderResolverTest::builder_;
} // 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 // GRPC_HAVE_UNIX_SOCKET
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1,133 +0,0 @@
# 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", "grpc_cc_test", "grpc_package")
licenses(["notice"])
grpc_package(
name = "test/core/transport/binder",
visibility = "tests",
)
grpc_cc_library(
name = "mock_objects",
testonly = 1,
srcs = ["mock_objects.cc"],
hdrs = ["mock_objects.h"],
external_deps = [
"absl/memory",
"gtest",
],
language = "C++",
deps = [
"//:grpc++_binder",
],
)
grpc_cc_test(
name = "wire_writer_test",
srcs = ["wire_writer_test.cc"],
external_deps = [
"absl/memory",
"gtest",
],
language = "C++",
tags = ["no_test_ios"],
uses_event_engine = False,
uses_polling = False,
deps = [
":mock_objects",
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
],
)
grpc_cc_test(
name = "wire_reader_test",
srcs = ["wire_reader_test.cc"],
external_deps = [
"absl/memory",
"gtest",
],
language = "C++",
tags = ["no_test_ios"],
uses_event_engine = False,
uses_polling = False,
deps = [
":mock_objects",
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
],
)
grpc_cc_test(
name = "transport_stream_receiver_test",
srcs = ["transport_stream_receiver_test.cc"],
external_deps = [
"absl/memory",
"gtest",
],
language = "C++",
tags = ["no_test_ios"],
uses_event_engine = False,
uses_polling = False,
deps = [
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
],
)
grpc_cc_test(
name = "binder_transport_test",
srcs = ["binder_transport_test.cc"],
external_deps = [
"absl/memory",
"absl/strings",
"gtest",
],
language = "C++",
tags = [
# To avoid `symbolizer buffer too small` warning of UBSAN
"noubsan",
"no_test_ios",
],
uses_event_engine = False,
uses_polling = False,
deps = [
":mock_objects",
"//:grpc",
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
],
)
grpc_cc_test(
name = "endpoint_binder_pool_test",
srcs = ["endpoint_binder_pool_test.cc"],
external_deps = [
"absl/memory",
"gtest",
],
language = "C++",
tags = ["no_test_ios"],
uses_event_engine = False,
uses_polling = False,
deps = [
":mock_objects",
"//:grpc",
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
],
)

@ -1,729 +0,0 @@
// 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.
// Unit-tests for grpc_binder_transport
//
// Verify that a calls to the perform_stream_op of grpc_binder_transport
// transform into the correct sequence of binder transactions.
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include <grpc/grpc.h>
#include <grpcpp/security/binder_security_policy.h>
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/strings/match.h"
#include "absl/strings/str_join.h"
#include "src/core/ext/transport/binder/transport/binder_stream.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/util/notification.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/mock_objects.h"
namespace grpc_binder {
namespace {
using ::testing::Expectation;
using ::testing::NiceMock;
using ::testing::Return;
class BinderTransportTest : public ::testing::Test {
public:
BinderTransportTest()
: transport_(grpc_create_binder_transport_client(
std::make_unique<NiceMock<MockBinder>>(),
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>())) {
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
gbt->wire_writer = std::make_unique<MockWireWriter>();
GRPC_STREAM_REF_INIT(&ref_, 1, nullptr, nullptr, "phony ref");
}
~BinderTransportTest() override {
grpc_core::ExecCtx exec_ctx;
transport_->Orphan();
grpc_core::ExecCtx::Get()->Flush();
for (grpc_binder_stream* gbs : stream_buffer_) {
gbs->~grpc_binder_stream();
gpr_free(gbs);
}
}
void PerformStreamOp(grpc_binder_stream* gbs,
grpc_transport_stream_op_batch* op) {
transport_->filter_stack_transport()->PerformStreamOp(
reinterpret_cast<grpc_stream*>(gbs), op);
}
grpc_binder_transport* GetBinderTransport() {
return reinterpret_cast<grpc_binder_transport*>(transport_);
}
grpc_binder_stream* InitNewBinderStream() {
grpc_binder_stream* gbs = static_cast<grpc_binder_stream*>(
gpr_malloc(transport_->filter_stack_transport()->SizeOfStream()));
transport_->filter_stack_transport()->InitStream(
reinterpret_cast<grpc_stream*>(gbs), &ref_, nullptr, arena_.get());
stream_buffer_.push_back(gbs);
return gbs;
}
MockWireWriter& GetWireWriter() {
return *reinterpret_cast<MockWireWriter*>(
GetBinderTransport()->wire_writer.get());
}
static void SetUpTestSuite() { grpc_init(); }
static void TearDownTestSuite() { grpc_shutdown(); }
protected:
grpc_core::RefCountedPtr<grpc_core::Arena> arena_ =
grpc_core::SimpleArenaAllocator()->MakeArena();
grpc_core::Transport* transport_;
grpc_stream_refcount ref_;
std::vector<grpc_binder_stream*> stream_buffer_;
};
void MockCallback(void* arg, grpc_error_handle error);
class MockGrpcClosure {
public:
explicit MockGrpcClosure(grpc_core::Notification* notification = nullptr)
: notification_(notification) {
GRPC_CLOSURE_INIT(&closure_, MockCallback, this, nullptr);
}
grpc_closure* GetGrpcClosure() { return &closure_; }
MOCK_METHOD(void, Callback, (grpc_error_handle), ());
grpc_core::Notification* notification_;
private:
grpc_closure closure_;
};
void MockCallback(void* arg, grpc_error_handle error) {
MockGrpcClosure* mock_closure = static_cast<MockGrpcClosure*>(arg);
mock_closure->Callback(error);
if (mock_closure->notification_) {
mock_closure->notification_->Notify();
}
}
std::string MetadataString(const Metadata& a) {
return absl::StrCat(
"{",
absl::StrJoin(
a, ", ",
[](std::string* out, const std::pair<std::string, std::string>& kv) {
out->append(
absl::StrCat("\"", kv.first, "\": \"", kv.second, "\""));
}),
"}");
}
bool MetadataEquivalent(Metadata a, Metadata b) {
std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());
return a == b;
}
// Matches with transactions having the desired flag, method_ref,
// initial_metadata, and message_data.
MATCHER_P4(TransactionMatches, flag, method_ref, initial_metadata, message_data,
"") {
if (arg->GetFlags() != flag) return false;
if (flag & kFlagPrefix) {
if (arg->GetMethodRef() != method_ref) {
printf("METHOD REF NOT EQ: %s %s\n",
std::string(arg->GetMethodRef()).c_str(),
std::string(method_ref).c_str());
return false;
}
if (!MetadataEquivalent(arg->GetPrefixMetadata(), initial_metadata)) {
printf("METADATA NOT EQUIVALENT: %s %s\n",
MetadataString(arg->GetPrefixMetadata()).c_str(),
MetadataString(initial_metadata).c_str());
return false;
}
}
if (flag & kFlagMessageData) {
if (arg->GetMessageData() != message_data) return false;
}
return true;
}
// Matches with grpc_error having error message containing |msg|.
MATCHER_P(GrpcErrorMessageContains, msg, "") {
return absl::StrContains(grpc_core::StatusToString(arg), msg);
}
namespace {
class MetadataEncoder {
public:
void Encode(const grpc_core::Slice& key, const grpc_core::Slice& value) {
metadata_.emplace_back(std::string(key.as_string_view()),
std::string(value.as_string_view()));
}
template <typename Which>
void Encode(Which, const typename Which::ValueType& value) {
metadata_.emplace_back(
std::string(Which::key()),
// NOLINTNEXTLINE(google-readability-casting)
std::string(grpc_core::Slice(Which::Encode(value)).as_string_view()));
}
const Metadata& metadata() const { return metadata_; }
private:
Metadata metadata_;
};
} // namespace
// Verify that the lower-level metadata has the same content as the gRPC
// metadata.
void VerifyMetadataEqual(const Metadata& md,
const grpc_metadata_batch& grpc_md) {
MetadataEncoder encoder;
grpc_md.Encode(&encoder);
EXPECT_TRUE(MetadataEquivalent(encoder.metadata(), md));
}
// RAII helper classes for constructing gRPC metadata and receiving callbacks.
struct MakeSendInitialMetadata {
MakeSendInitialMetadata(const Metadata& initial_metadata,
const std::string& method_ref,
grpc_transport_stream_op_batch* op) {
for (const auto& md : initial_metadata) {
const std::string& key = md.first;
const std::string& value = md.second;
grpc_initial_metadata.Append(
key, grpc_core::Slice::FromCopiedString(value),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
}
if (!method_ref.empty()) {
grpc_initial_metadata.Set(grpc_core::HttpPathMetadata(),
grpc_core::Slice::FromCopiedString(method_ref));
}
op->send_initial_metadata = true;
op->payload->send_initial_metadata.send_initial_metadata =
&grpc_initial_metadata;
}
~MakeSendInitialMetadata() {}
grpc_metadata_batch grpc_initial_metadata;
};
struct MakeSendMessage {
MakeSendMessage(const std::string& message,
grpc_transport_stream_op_batch* op) {
send_stream.Append(grpc_core::Slice::FromCopiedString(message));
op->send_message = true;
op->payload->send_message.send_message = &send_stream;
}
grpc_core::SliceBuffer send_stream;
};
struct MakeSendTrailingMetadata {
explicit MakeSendTrailingMetadata(const Metadata& trailing_metadata,
grpc_transport_stream_op_batch* op) {
EXPECT_TRUE(trailing_metadata.empty());
op->send_trailing_metadata = true;
op->payload->send_trailing_metadata.send_trailing_metadata =
&grpc_trailing_metadata;
}
grpc_core::MemoryAllocator memory_allocator =
grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
->memory_quota()
->CreateMemoryAllocator("test"));
grpc_metadata_batch grpc_trailing_metadata;
};
struct MakeRecvInitialMetadata {
explicit MakeRecvInitialMetadata(grpc_transport_stream_op_batch* op,
Expectation* call_before = nullptr)
: ready(&notification) {
op->recv_initial_metadata = true;
op->payload->recv_initial_metadata.recv_initial_metadata =
&grpc_initial_metadata;
op->payload->recv_initial_metadata.recv_initial_metadata_ready =
ready.GetGrpcClosure();
if (call_before) {
EXPECT_CALL(ready, Callback).After(*call_before);
} else {
EXPECT_CALL(ready, Callback);
}
}
~MakeRecvInitialMetadata() {}
MockGrpcClosure ready;
grpc_core::MemoryAllocator memory_allocator =
grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
->memory_quota()
->CreateMemoryAllocator("test"));
grpc_metadata_batch grpc_initial_metadata;
grpc_core::Notification notification;
};
struct MakeRecvMessage {
explicit MakeRecvMessage(grpc_transport_stream_op_batch* op,
Expectation* call_before = nullptr)
: ready(&notification) {
op->recv_message = true;
op->payload->recv_message.recv_message = &grpc_message;
op->payload->recv_message.recv_message_ready = ready.GetGrpcClosure();
if (call_before) {
EXPECT_CALL(ready, Callback).After(*call_before);
} else {
EXPECT_CALL(ready, Callback);
}
}
MockGrpcClosure ready;
grpc_core::Notification notification;
absl::optional<grpc_core::SliceBuffer> grpc_message;
};
struct MakeRecvTrailingMetadata {
explicit MakeRecvTrailingMetadata(grpc_transport_stream_op_batch* op,
Expectation* call_before = nullptr)
: ready(&notification) {
op->recv_trailing_metadata = true;
op->payload->recv_trailing_metadata.recv_trailing_metadata =
&grpc_trailing_metadata;
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready =
ready.GetGrpcClosure();
if (call_before) {
EXPECT_CALL(ready, Callback).After(*call_before);
} else {
EXPECT_CALL(ready, Callback);
}
}
~MakeRecvTrailingMetadata() {}
MockGrpcClosure ready;
grpc_core::MemoryAllocator memory_allocator =
grpc_core::MemoryAllocator(grpc_core::ResourceQuota::Default()
->memory_quota()
->CreateMemoryAllocator("test"));
grpc_metadata_batch grpc_trailing_metadata;
grpc_core::Notification notification;
};
const Metadata kDefaultMetadata = {
{"", ""},
{"", "value"},
{"key", ""},
{"key", "value"},
};
constexpr char kDefaultMethodRef[] = "/some/path";
constexpr char kDefaultMessage[] = "binder transport message";
constexpr int kDefaultStatus = 0x1234;
Metadata AppendMethodRef(const Metadata& md, const std::string& method_ref) {
Metadata result = md;
result.emplace_back(":path", method_ref);
return result;
}
Metadata AppendStatus(const Metadata& md, int status) {
Metadata result = md;
result.emplace_back("grpc-status", std::to_string(status));
return result;
}
} // namespace
TEST_F(BinderTransportTest, CreateBinderTransport) {
EXPECT_NE(transport_, nullptr);
}
TEST_F(BinderTransportTest, TransactionIdIncrement) {
grpc_binder_stream* gbs0 = InitNewBinderStream();
EXPECT_EQ(gbs0->t, GetBinderTransport());
EXPECT_EQ(gbs0->tx_code, kFirstCallId);
grpc_binder_stream* gbs1 = InitNewBinderStream();
EXPECT_EQ(gbs1->t, GetBinderTransport());
EXPECT_EQ(gbs1->tx_code, kFirstCallId + 1);
grpc_binder_stream* gbs2 = InitNewBinderStream();
EXPECT_EQ(gbs2->t, GetBinderTransport());
EXPECT_EQ(gbs2->tx_code, kFirstCallId + 2);
}
TEST_F(BinderTransportTest, PerformSendInitialMetadata) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
const Metadata kInitialMetadata = kDefaultMetadata;
MakeSendInitialMetadata send_initial_metadata(kInitialMetadata, "", &op);
MockGrpcClosure mock_on_complete;
op.on_complete = mock_on_complete.GetGrpcClosure();
::testing::InSequence sequence;
EXPECT_CALL(GetWireWriter(), RpcCall(TransactionMatches(
kFlagPrefix, "", kInitialMetadata, "")));
EXPECT_CALL(mock_on_complete, Callback);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
}
TEST_F(BinderTransportTest, PerformSendInitialMetadataMethodRef) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
const Metadata kInitialMetadata = kDefaultMetadata;
const std::string kMethodRef = kDefaultMethodRef;
MakeSendInitialMetadata send_initial_metadata(kInitialMetadata, kMethodRef,
&op);
MockGrpcClosure mock_on_complete;
op.on_complete = mock_on_complete.GetGrpcClosure();
::testing::InSequence sequence;
EXPECT_CALL(GetWireWriter(),
RpcCall(TransactionMatches(kFlagPrefix, kMethodRef.substr(1),
kInitialMetadata, "")));
EXPECT_CALL(mock_on_complete, Callback);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
}
TEST_F(BinderTransportTest, PerformSendMessage) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
const std::string kMessage = kDefaultMessage;
MakeSendMessage send_message(kMessage, &op);
MockGrpcClosure mock_on_complete;
op.on_complete = mock_on_complete.GetGrpcClosure();
::testing::InSequence sequence;
EXPECT_CALL(
GetWireWriter(),
RpcCall(TransactionMatches(kFlagMessageData, "", Metadata{}, kMessage)));
EXPECT_CALL(mock_on_complete, Callback);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
}
TEST_F(BinderTransportTest, PerformSendTrailingMetadata) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
// The wireformat guarantees that suffix metadata will always be empty.
// TODO(waynetu): Check whether gRPC can internally add extra trailing
// metadata.
const Metadata kTrailingMetadata = {};
MakeSendTrailingMetadata send_trailing_metadata(kTrailingMetadata, &op);
MockGrpcClosure mock_on_complete;
op.on_complete = mock_on_complete.GetGrpcClosure();
::testing::InSequence sequence;
EXPECT_CALL(GetWireWriter(), RpcCall(TransactionMatches(
kFlagSuffix, "", kTrailingMetadata, "")));
EXPECT_CALL(mock_on_complete, Callback);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
}
TEST_F(BinderTransportTest, PerformSendAll) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
const Metadata kInitialMetadata = kDefaultMetadata;
const std::string kMethodRef = kDefaultMethodRef;
MakeSendInitialMetadata send_initial_metadata(kInitialMetadata, kMethodRef,
&op);
const std::string kMessage = kDefaultMessage;
MakeSendMessage send_message(kMessage, &op);
// The wireformat guarantees that suffix metadata will always be empty.
// TODO(waynetu): Check whether gRPC can internally add extra trailing
// metadata.
const Metadata kTrailingMetadata = {};
MakeSendTrailingMetadata send_trailing_metadata(kTrailingMetadata, &op);
MockGrpcClosure mock_on_complete;
op.on_complete = mock_on_complete.GetGrpcClosure();
::testing::InSequence sequence;
EXPECT_CALL(GetWireWriter(),
RpcCall(TransactionMatches(
kFlagPrefix | kFlagMessageData | kFlagSuffix,
kMethodRef.substr(1), kInitialMetadata, kMessage)));
EXPECT_CALL(mock_on_complete, Callback);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
}
TEST_F(BinderTransportTest, PerformRecvInitialMetadata) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
MakeRecvInitialMetadata recv_initial_metadata(&op);
const Metadata kInitialMetadata = kDefaultMetadata;
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
gbt->transport_stream_receiver->NotifyRecvInitialMetadata(gbs->tx_code,
kInitialMetadata);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
recv_initial_metadata.notification.WaitForNotification();
VerifyMetadataEqual(kInitialMetadata,
recv_initial_metadata.grpc_initial_metadata);
}
TEST_F(BinderTransportTest, PerformRecvInitialMetadataWithMethodRef) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
MakeRecvInitialMetadata recv_initial_metadata(&op);
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
const Metadata kInitialMetadataWithMethodRef =
AppendMethodRef(kDefaultMetadata, kDefaultMethodRef);
gbt->transport_stream_receiver->NotifyRecvInitialMetadata(
gbs->tx_code, kInitialMetadataWithMethodRef);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
recv_initial_metadata.notification.WaitForNotification();
VerifyMetadataEqual(kInitialMetadataWithMethodRef,
recv_initial_metadata.grpc_initial_metadata);
}
TEST_F(BinderTransportTest, PerformRecvMessage) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
MakeRecvMessage recv_message(&op);
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
const std::string kMessage = kDefaultMessage;
gbt->transport_stream_receiver->NotifyRecvMessage(gbs->tx_code, kMessage);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
recv_message.notification.WaitForNotification();
EXPECT_EQ(kMessage, recv_message.grpc_message->JoinIntoString());
}
TEST_F(BinderTransportTest, PerformRecvTrailingMetadata) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
MakeRecvTrailingMetadata recv_trailing_metadata(&op);
const Metadata kTrailingMetadata = kDefaultMetadata;
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
constexpr int kStatus = kDefaultStatus;
gbt->transport_stream_receiver->NotifyRecvTrailingMetadata(
gbs->tx_code, kTrailingMetadata, kStatus);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
recv_trailing_metadata.notification.WaitForNotification();
VerifyMetadataEqual(AppendStatus(kTrailingMetadata, kStatus),
recv_trailing_metadata.grpc_trailing_metadata);
}
TEST_F(BinderTransportTest, PerformRecvAll) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
MakeRecvInitialMetadata recv_initial_metadata(&op);
MakeRecvMessage recv_message(&op);
MakeRecvTrailingMetadata recv_trailing_metadata(&op);
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
const Metadata kInitialMetadataWithMethodRef =
AppendMethodRef(kDefaultMetadata, kDefaultMethodRef);
gbt->transport_stream_receiver->NotifyRecvInitialMetadata(
gbs->tx_code, kInitialMetadataWithMethodRef);
const std::string kMessage = kDefaultMessage;
gbt->transport_stream_receiver->NotifyRecvMessage(gbs->tx_code, kMessage);
Metadata trailing_metadata = kDefaultMetadata;
constexpr int kStatus = kDefaultStatus;
gbt->transport_stream_receiver->NotifyRecvTrailingMetadata(
gbs->tx_code, trailing_metadata, kStatus);
PerformStreamOp(gbs, &op);
grpc_core::ExecCtx::Get()->Flush();
recv_trailing_metadata.notification.WaitForNotification();
VerifyMetadataEqual(kInitialMetadataWithMethodRef,
recv_initial_metadata.grpc_initial_metadata);
trailing_metadata.emplace_back("grpc-status", std::to_string(kStatus));
VerifyMetadataEqual(trailing_metadata,
recv_trailing_metadata.grpc_trailing_metadata);
EXPECT_EQ(kMessage, recv_message.grpc_message->JoinIntoString());
}
TEST_F(BinderTransportTest, PerformAllOps) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
grpc_transport_stream_op_batch op{};
grpc_transport_stream_op_batch_payload payload;
op.payload = &payload;
const Metadata kSendInitialMetadata = kDefaultMetadata;
const std::string kMethodRef = kDefaultMethodRef;
MakeSendInitialMetadata send_initial_metadata(kSendInitialMetadata,
kMethodRef, &op);
const std::string kSendMessage = kDefaultMessage;
MakeSendMessage send_message(kSendMessage, &op);
// The wireformat guarantees that suffix metadata will always be empty.
// TODO(waynetu): Check whether gRPC can internally add extra trailing
// metadata.
const Metadata kSendTrailingMetadata = {};
MakeSendTrailingMetadata send_trailing_metadata(kSendTrailingMetadata, &op);
MockGrpcClosure mock_on_complete;
op.on_complete = mock_on_complete.GetGrpcClosure();
// TODO(waynetu): Currently, we simply drop the prefix '/' from the :path
// argument to obtain the method name. Update the test if this turns out to be
// incorrect.
EXPECT_CALL(GetWireWriter(),
RpcCall(TransactionMatches(
kFlagPrefix | kFlagMessageData | kFlagSuffix,
kMethodRef.substr(1), kSendInitialMetadata, kSendMessage)));
Expectation on_complete = EXPECT_CALL(mock_on_complete, Callback);
// Recv callbacks can happen after the on_complete callback.
MakeRecvInitialMetadata recv_initial_metadata(
&op, /* call_before = */ &on_complete);
MakeRecvMessage recv_message(&op, /* call_before = */ &on_complete);
MakeRecvTrailingMetadata recv_trailing_metadata(
&op, /* call_before = */ &on_complete);
PerformStreamOp(gbs, &op);
// Flush the execution context to force on_complete to run before recv
// callbacks get scheduled.
grpc_core::ExecCtx::Get()->Flush();
auto* gbt = reinterpret_cast<grpc_binder_transport*>(transport_);
const Metadata kRecvInitialMetadata =
AppendMethodRef(kDefaultMetadata, kDefaultMethodRef);
gbt->transport_stream_receiver->NotifyRecvInitialMetadata(
gbs->tx_code, kRecvInitialMetadata);
const std::string kRecvMessage = kDefaultMessage;
gbt->transport_stream_receiver->NotifyRecvMessage(gbs->tx_code, kRecvMessage);
const Metadata kRecvTrailingMetadata = kDefaultMetadata;
constexpr int kStatus = 0x1234;
gbt->transport_stream_receiver->NotifyRecvTrailingMetadata(
gbs->tx_code, kRecvTrailingMetadata, kStatus);
grpc_core::ExecCtx::Get()->Flush();
recv_initial_metadata.notification.WaitForNotification();
recv_message.notification.WaitForNotification();
recv_trailing_metadata.notification.WaitForNotification();
VerifyMetadataEqual(kRecvInitialMetadata,
recv_initial_metadata.grpc_initial_metadata);
VerifyMetadataEqual(AppendStatus(kRecvTrailingMetadata, kStatus),
recv_trailing_metadata.grpc_trailing_metadata);
EXPECT_EQ(kRecvMessage, recv_message.grpc_message->JoinIntoString());
}
TEST_F(BinderTransportTest, WireWriterRpcCallErrorPropagates) {
grpc_core::ExecCtx exec_ctx;
grpc_binder_stream* gbs = InitNewBinderStream();
MockGrpcClosure mock_on_complete1;
MockGrpcClosure mock_on_complete2;
EXPECT_CALL(GetWireWriter(), RpcCall)
.WillOnce(Return(absl::OkStatus()))
.WillOnce(Return(absl::InternalError("WireWriter::RpcCall failed")));
EXPECT_CALL(mock_on_complete1, Callback(absl::OkStatus()));
EXPECT_CALL(mock_on_complete2,
Callback(GrpcErrorMessageContains("WireWriter::RpcCall failed")));
const Metadata kInitialMetadata = {};
grpc_transport_stream_op_batch op1{};
grpc_transport_stream_op_batch_payload payload1;
op1.payload = &payload1;
MakeSendInitialMetadata send_initial_metadata1(kInitialMetadata, "", &op1);
op1.on_complete = mock_on_complete1.GetGrpcClosure();
grpc_transport_stream_op_batch op2{};
grpc_transport_stream_op_batch_payload payload2;
op2.payload = &payload2;
MakeSendInitialMetadata send_initial_metadata2(kInitialMetadata, "", &op2);
op2.on_complete = mock_on_complete2.GetGrpcClosure();
PerformStreamOp(gbs, &op1);
PerformStreamOp(gbs, &op2);
grpc_core::ExecCtx::Get()->Flush();
}
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1,119 +0,0 @@
# 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", "grpc_cc_test", "grpc_package")
licenses(["notice"])
grpc_package(
name = "test/core/transport/binder/end2end",
visibility = "tests",
)
grpc_cc_library(
name = "fake_binder",
testonly = 1,
srcs = ["fake_binder.cc"],
hdrs = ["fake_binder.h"],
external_deps = [
"absl/log:log",
"absl/memory",
"absl/random",
"absl/strings",
"absl/strings:str_format",
"absl/time",
"absl/types:variant",
],
deps = [
"//:gpr",
"//:grpc++_binder",
],
)
grpc_cc_test(
name = "fake_binder_test",
srcs = ["fake_binder_test.cc"],
external_deps = [
"absl/strings",
"absl/time",
"gtest",
],
language = "C++",
tags = ["no_test_ios"],
uses_event_engine = False,
uses_polling = False,
deps = [
":fake_binder",
"//test/core/test_util:grpc_test_util",
],
)
grpc_cc_library(
name = "end2end_binder_channel",
testonly = 1,
srcs = ["testing_channel_create.cc"],
hdrs = ["testing_channel_create.h"],
external_deps = ["absl/log:check"],
deps = [
":fake_binder",
"//:grpc++_base",
"//:grpc++_binder",
"//:grpc_base",
"//src/core:channel_args",
],
)
grpc_cc_test(
name = "end2end_binder_transport_test",
srcs = ["end2end_binder_transport_test.cc"],
external_deps = [
"absl/memory",
"absl/time",
"gtest",
],
flaky = True,
language = "C++",
tags = [
# Flaky on windows
"no_windows",
"no_mac",
"no_test_ios",
# Known race between stream creation and cancellation
"notsan",
],
deps = [
":end2end_binder_channel",
":fake_binder",
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
"//test/cpp/end2end:test_service_impl",
],
)
grpc_cc_test(
name = "binder_server_test",
srcs = ["binder_server_test.cc"],
external_deps = [
"gtest",
],
tags = ["no_test_ios"],
deps = [
"//:grpc++",
"//:grpc++_binder",
"//test/core/test_util:grpc_test_util",
"//test/core/transport/binder/end2end:fake_binder",
"//test/cpp/end2end:test_service_impl",
],
)

@ -1,243 +0,0 @@
// 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 <grpcpp/grpcpp.h>
#include <grpcpp/security/binder_credentials.h>
#include <grpcpp/security/binder_security_policy.h>
#include <gtest/gtest.h>
#include <memory>
#include <thread>
#include <vector>
#include "absl/memory/memory.h"
#include "src/core/ext/transport/binder/client/channel_create_impl.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/end2end/fake_binder.h"
#include "test/cpp/end2end/test_service_impl.h"
namespace grpc {
namespace testing {
namespace {
class BinderServerCredentialsImpl final : public ServerCredentials {
public:
BinderServerCredentialsImpl() : ServerCredentials(nullptr) {}
int AddPortToServer(const std::string& addr, grpc_server* server) override {
return grpc_core::AddBinderPort(
addr, server,
[](grpc_binder::TransactionReceiver::OnTransactCb transact_cb) {
return std::make_unique<
grpc_binder::end2end_testing::FakeTransactionReceiver>(
nullptr, std::move(transact_cb));
},
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>());
}
};
} // namespace
std::shared_ptr<ServerCredentials> BinderServerCredentials() {
return std::shared_ptr<ServerCredentials>(new BinderServerCredentialsImpl());
}
std::shared_ptr<grpc::Channel> CreateBinderChannel(
std::unique_ptr<grpc_binder::Binder> endpoint_binder) {
return grpc::CreateChannelInternal(
"",
grpc::internal::CreateDirectBinderChannelImplForTesting(
std::move(endpoint_binder), nullptr,
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>()),
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>());
}
} // 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(); }
static void TearDownTestSuite() { grpc_shutdown(); }
};
#ifndef GPR_SUPPORT_BINDER_TRANSPORT
TEST(BinderServerCredentialsTest,
FailedInEnvironmentsNotSupportingBinderTransport) {
grpc::ServerBuilder server_builder;
grpc::testing::TestServiceImpl service;
server_builder.RegisterService(&service);
server_builder.AddListeningPort(
"binder:fail",
grpc::experimental::BinderServerCredentials(
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>()));
EXPECT_EQ(server_builder.BuildAndStart(), nullptr);
}
#endif // !GPR_SUPPORT_BINDER_TRANSPORT
TEST_F(BinderServerTest, BuildAndStart) {
grpc::ServerBuilder server_builder;
grpc::testing::TestServiceImpl service;
server_builder.RegisterService(&service);
server_builder.AddListeningPort("binder:example.service",
grpc::testing::BinderServerCredentials());
std::unique_ptr<grpc::Server> 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::testing::TestServiceImpl service;
server_builder.RegisterService(&service);
// Error: binder address should begin with binder:
server_builder.AddListeningPort("localhost:12345",
grpc::testing::BinderServerCredentials());
std::unique_ptr<grpc::Server> server = server_builder.BuildAndStart();
EXPECT_EQ(server, nullptr);
}
TEST_F(BinderServerTest, CreateChannelWithEndpointBinder) {
grpc::ServerBuilder server_builder;
grpc::testing::TestServiceImpl service;
server_builder.RegisterService(&service);
server_builder.AddListeningPort("binder:example.service",
grpc::testing::BinderServerCredentials());
std::unique_ptr<grpc::Server> server = server_builder.BuildAndStart();
void* raw_endpoint_binder =
grpc::experimental::binder::GetEndpointBinder("example.service");
std::unique_ptr<grpc_binder::Binder> endpoint_binder =
std::make_unique<grpc_binder::end2end_testing::FakeBinder>(
static_cast<grpc_binder::end2end_testing::FakeEndpoint*>(
raw_endpoint_binder));
std::shared_ptr<grpc::Channel> channel =
grpc::testing::CreateBinderChannel(std::move(endpoint_binder));
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub =
grpc::testing::EchoTestService::NewStub(channel);
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
grpc::ClientContext context;
request.set_message("BinderServerBuilder");
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_TRUE(status.ok());
EXPECT_EQ(response.message(), "BinderServerBuilder");
server->Shutdown();
}
TEST_F(BinderServerTest, CreateChannelWithEndpointBinderMultipleConnections) {
grpc::ServerBuilder server_builder;
grpc::testing::TestServiceImpl service;
server_builder.RegisterService(&service);
server_builder.AddListeningPort("binder:example.service.multiple.connections",
grpc::testing::BinderServerCredentials());
std::unique_ptr<grpc::Server> server = server_builder.BuildAndStart();
void* raw_endpoint_binder = grpc::experimental::binder::GetEndpointBinder(
"example.service.multiple.connections");
constexpr size_t kNumThreads = 10;
auto thread_fn = [&](size_t id) {
std::unique_ptr<grpc_binder::Binder> endpoint_binder =
std::make_unique<grpc_binder::end2end_testing::FakeBinder>(
static_cast<grpc_binder::end2end_testing::FakeEndpoint*>(
raw_endpoint_binder));
std::shared_ptr<grpc::Channel> channel =
grpc::testing::CreateBinderChannel(std::move(endpoint_binder));
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub =
grpc::testing::EchoTestService::NewStub(channel);
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
grpc::ClientContext context;
request.set_message(absl::StrFormat("BinderServerBuilder-%d", id));
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_TRUE(status.ok());
EXPECT_EQ(response.message(),
absl::StrFormat("BinderServerBuilder-%d", id));
};
std::vector<std::thread> 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();
}
TEST_F(BinderServerTest, CreateChannelWithEndpointBinderParallelRequests) {
grpc::ServerBuilder server_builder;
grpc::testing::TestServiceImpl service;
server_builder.RegisterService(&service);
server_builder.AddListeningPort("binder:example.service",
grpc::testing::BinderServerCredentials());
std::unique_ptr<grpc::Server> server = server_builder.BuildAndStart();
void* raw_endpoint_binder =
grpc::experimental::binder::GetEndpointBinder("example.service");
std::unique_ptr<grpc_binder::Binder> endpoint_binder =
std::make_unique<grpc_binder::end2end_testing::FakeBinder>(
static_cast<grpc_binder::end2end_testing::FakeEndpoint*>(
raw_endpoint_binder));
std::shared_ptr<grpc::Channel> channel =
grpc::testing::CreateBinderChannel(std::move(endpoint_binder));
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub =
grpc::testing::EchoTestService::NewStub(channel);
constexpr size_t kNumRequests = 10;
auto thread_fn = [&](size_t id) {
grpc::testing::EchoRequest request;
std::string msg = absl::StrFormat("BinderServerBuilder-%d", id);
request.set_message(msg);
grpc::testing::EchoResponse response;
grpc::ClientContext context;
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_TRUE(status.ok());
EXPECT_EQ(response.message(), msg);
};
std::vector<std::thread> threads(kNumRequests);
for (size_t i = 0; i < kNumRequests; ++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();
}

@ -1,566 +0,0 @@
// 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 <gmock/gmock.h>
#include <grpcpp/grpcpp.h>
#include <gtest/gtest.h>
#include <string>
#include <thread>
#include <utility>
#include "absl/memory/memory.h"
#include "absl/time/time.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader_impl.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/end2end/fake_binder.h"
#include "test/core/transport/binder/end2end/testing_channel_create.h"
#include "test/cpp/end2end/test_service_impl.h"
namespace grpc_binder {
namespace {
class End2EndBinderTransportTest
: public ::testing::TestWithParam<absl::Duration> {
public:
End2EndBinderTransportTest() {
end2end_testing::g_transaction_processor =
new end2end_testing::TransactionProcessor(GetParam());
service_ = std::make_unique<grpc::testing::TestServiceImpl>();
grpc::ServerBuilder builder;
builder.RegisterService(service_.get());
server_ = builder.BuildAndStart();
}
~End2EndBinderTransportTest() override {
server_->Shutdown();
service_.reset();
exec_ctx.Flush();
delete end2end_testing::g_transaction_processor;
}
std::unique_ptr<grpc::testing::EchoTestService::Stub> NewStub() {
grpc::ChannelArguments args;
std::shared_ptr<grpc::Channel> channel = BinderChannel(server_.get(), args);
return grpc::testing::EchoTestService::NewStub(channel);
}
static void SetUpTestSuite() { grpc_init(); }
static void TearDownTestSuite() { grpc_shutdown(); }
std::shared_ptr<grpc::Channel> BinderChannel(
grpc::Server* server, const grpc::ChannelArguments& args) {
return end2end_testing::BinderChannelForTesting(server, args);
}
protected:
std::unique_ptr<grpc::testing::TestServiceImpl> service_;
std::unique_ptr<grpc::Server> server_;
private:
grpc_core::ExecCtx exec_ctx;
};
} // namespace
TEST_P(End2EndBinderTransportTest, SetupTransport) {
grpc_core::Transport *client_transport, *server_transport;
std::tie(client_transport, server_transport) =
end2end_testing::CreateClientServerBindersPairForTesting();
EXPECT_NE(client_transport, nullptr);
EXPECT_NE(server_transport, nullptr);
client_transport->Orphan();
server_transport->Orphan();
}
TEST_P(End2EndBinderTransportTest, UnaryCall) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCall");
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_TRUE(status.ok());
EXPECT_EQ(response.message(), "UnaryCall");
}
TEST_P(End2EndBinderTransportTest, UnaryCallWithNonOkStatus) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallWithNonOkStatus");
request.mutable_param()->mutable_expected_error()->set_code(
grpc::StatusCode::INTERNAL);
request.mutable_param()->mutable_expected_error()->set_error_message(
"expected to fail");
// Server will not response the client with message data, however, since all
// callbacks after the trailing metadata are cancelled, we shall not be
// blocked here.
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::INTERNAL);
EXPECT_THAT(status.error_message(), ::testing::HasSubstr("expected to fail"));
}
// Disabled because the test is ~0.01% flaky
TEST_P(End2EndBinderTransportTest, DISABLED_UnaryCallServerTimeout) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
context.set_deadline(absl::ToChronoTime(
absl::Now() + (absl::Seconds(1) * grpc_test_slowdown_factor())));
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallServerTimeout");
// Server will sleep for 2 seconds before responding us.
request.mutable_param()->set_server_sleep_us(2000000);
// Disable cancellation check because the request will time out.
request.mutable_param()->set_skip_cancelled_check(true);
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED);
}
TEST_P(End2EndBinderTransportTest, UnaryCallClientTimeout) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
// Set transaction delay to a large number. This happens after the channel
// creation so that we don't need to wait that long for client and server to
// be connected.
end2end_testing::g_transaction_processor->SetDelay(absl::Seconds(5));
grpc::ClientContext context;
context.set_deadline(absl::ToChronoTime(absl::Now() + absl::Seconds(1)));
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallClientTimeout");
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::DEADLINE_EXCEEDED);
}
TEST_P(End2EndBinderTransportTest, UnaryCallUnimplemented) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallUnimplemented");
grpc::Status status = stub->Unimplemented(&context, request, &response);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::UNIMPLEMENTED);
}
TEST_P(End2EndBinderTransportTest, UnaryCallClientCancel) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallClientCancel");
context.TryCancel();
grpc::Status status = stub->Unimplemented(&context, request, &response);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest, UnaryCallEchoMetadataInitially) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallEchoMetadataInitially");
request.mutable_param()->set_echo_metadata_initially(true);
context.AddMetadata("key1", "value1");
context.AddMetadata("key2", "value2");
grpc::Status status = stub->Echo(&context, request, &response);
const auto& initial_metadata = context.GetServerInitialMetadata();
EXPECT_EQ(initial_metadata.find("key1")->second, "value1");
EXPECT_EQ(initial_metadata.find("key2")->second, "value2");
}
TEST_P(End2EndBinderTransportTest, UnaryCallEchoMetadata) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallEchoMetadata");
request.mutable_param()->set_echo_metadata(true);
context.AddMetadata("key1", "value1");
context.AddMetadata("key2", "value2");
grpc::Status status = stub->Echo(&context, request, &response);
const auto& initial_metadata = context.GetServerTrailingMetadata();
EXPECT_EQ(initial_metadata.find("key1")->second, "value1");
EXPECT_EQ(initial_metadata.find("key2")->second, "value2");
}
TEST_P(End2EndBinderTransportTest, UnaryCallResponseMessageLength) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
for (size_t response_length : {1, 2, 5, 10, 100, 1000000}) {
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallResponseMessageLength");
request.mutable_param()->set_response_message_length(response_length);
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_EQ(response.message().length(), response_length);
}
}
TEST_P(End2EndBinderTransportTest, UnaryCallTryCancel) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_BEFORE_PROCESSING));
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message("UnaryCallTryCancel");
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest, ServerStreamingCall) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
constexpr size_t kServerResponseStreamsToSend = 100;
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerResponseStreamsToSend,
std::to_string(kServerResponseStreamsToSend));
grpc::testing::EchoRequest request;
request.set_message("ServerStreamingCall");
std::unique_ptr<grpc::ClientReader<grpc::testing::EchoResponse>> reader =
stub->ResponseStream(&context, request);
grpc::testing::EchoResponse response;
size_t cnt = 0;
while (reader->Read(&response)) {
EXPECT_EQ(response.message(), "ServerStreamingCall" + std::to_string(cnt));
cnt++;
}
EXPECT_EQ(cnt, kServerResponseStreamsToSend);
grpc::Status status = reader->Finish();
EXPECT_TRUE(status.ok());
}
TEST_P(End2EndBinderTransportTest, ServerStreamingCallCoalescingApi) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
constexpr size_t kServerResponseStreamsToSend = 100;
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerResponseStreamsToSend,
std::to_string(kServerResponseStreamsToSend));
context.AddMetadata(grpc::testing::kServerUseCoalescingApi, "1");
grpc::testing::EchoRequest request;
request.set_message("ServerStreamingCallCoalescingApi");
std::unique_ptr<grpc::ClientReader<grpc::testing::EchoResponse>> reader =
stub->ResponseStream(&context, request);
grpc::testing::EchoResponse response;
size_t cnt = 0;
while (reader->Read(&response)) {
EXPECT_EQ(response.message(),
"ServerStreamingCallCoalescingApi" + std::to_string(cnt));
cnt++;
}
EXPECT_EQ(cnt, kServerResponseStreamsToSend);
grpc::Status status = reader->Finish();
EXPECT_TRUE(status.ok());
}
TEST_P(End2EndBinderTransportTest,
ServerStreamingCallTryCancelBeforeProcessing) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
constexpr size_t kServerResponseStreamsToSend = 100;
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerResponseStreamsToSend,
std::to_string(kServerResponseStreamsToSend));
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_BEFORE_PROCESSING));
grpc::testing::EchoRequest request;
request.set_message("ServerStreamingCallTryCancelBeforeProcessing");
std::unique_ptr<grpc::ClientReader<grpc::testing::EchoResponse>> reader =
stub->ResponseStream(&context, request);
grpc::testing::EchoResponse response;
EXPECT_FALSE(reader->Read(&response));
grpc::Status status = reader->Finish();
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest,
ServerSteramingCallTryCancelDuringProcessing) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
constexpr size_t kServerResponseStreamsToSend = 2;
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerResponseStreamsToSend,
std::to_string(kServerResponseStreamsToSend));
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_DURING_PROCESSING));
grpc::testing::EchoRequest request;
request.set_message("ServerStreamingCallTryCancelDuringProcessing");
std::unique_ptr<grpc::ClientReader<grpc::testing::EchoResponse>> reader =
stub->ResponseStream(&context, request);
grpc::testing::EchoResponse response;
size_t cnt = 0;
while (reader->Read(&response)) {
EXPECT_EQ(
response.message(),
"ServerStreamingCallTryCancelDuringProcessing" + std::to_string(cnt));
cnt++;
}
grpc::Status status = reader->Finish();
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest,
ServerSteramingCallTryCancelAfterProcessing) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
constexpr size_t kServerResponseStreamsToSend = 100;
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerResponseStreamsToSend,
std::to_string(kServerResponseStreamsToSend));
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_AFTER_PROCESSING));
grpc::testing::EchoRequest request;
request.set_message("ServerStreamingCallTryCancelAfterProcessing");
std::unique_ptr<grpc::ClientReader<grpc::testing::EchoResponse>> reader =
stub->ResponseStream(&context, request);
grpc::testing::EchoResponse response;
size_t cnt = 0;
while (reader->Read(&response)) {
EXPECT_EQ(
response.message(),
"ServerStreamingCallTryCancelAfterProcessing" + std::to_string(cnt));
cnt++;
}
EXPECT_EQ(cnt, kServerResponseStreamsToSend);
grpc::Status status = reader->Finish();
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest, ClientStreamingCall) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
grpc::testing::EchoResponse response;
std::unique_ptr<grpc::ClientWriter<grpc::testing::EchoRequest>> writer =
stub->RequestStream(&context, &response);
constexpr size_t kClientStreamingCounts = 100;
std::string expected;
for (size_t i = 0; i < kClientStreamingCounts; ++i) {
grpc::testing::EchoRequest request;
request.set_message("ClientStreamingCall" + std::to_string(i));
EXPECT_TRUE(writer->Write(request));
expected += "ClientStreamingCall" + std::to_string(i);
}
writer->WritesDone();
grpc::Status status = writer->Finish();
EXPECT_TRUE(status.ok());
EXPECT_EQ(response.message(), expected);
}
// Disabled because the test case is ~0.002% flaky
TEST_P(End2EndBinderTransportTest,
DISABLED_ClientStreamingCallTryCancelBeforeProcessing) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_BEFORE_PROCESSING));
grpc::testing::EchoResponse response;
std::unique_ptr<grpc::ClientWriter<grpc::testing::EchoRequest>> writer =
stub->RequestStream(&context, &response);
constexpr size_t kClientStreamingCounts = 100;
for (size_t i = 0; i < kClientStreamingCounts; ++i) {
grpc::testing::EchoRequest request;
request.set_message("ClientStreamingCallBeforeProcessing" +
std::to_string(i));
writer->Write(request);
}
writer->WritesDone();
grpc::Status status = writer->Finish();
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
// Disabled because the test case is ~0.002% flaky
TEST_P(End2EndBinderTransportTest,
DISABLED_ClientStreamingCallTryCancelDuringProcessing) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_DURING_PROCESSING));
grpc::testing::EchoResponse response;
std::unique_ptr<grpc::ClientWriter<grpc::testing::EchoRequest>> writer =
stub->RequestStream(&context, &response);
constexpr size_t kClientStreamingCounts = 100;
for (size_t i = 0; i < kClientStreamingCounts; ++i) {
grpc::testing::EchoRequest request;
request.set_message("ClientStreamingCallDuringProcessing" +
std::to_string(i));
writer->Write(request);
}
writer->WritesDone();
grpc::Status status = writer->Finish();
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest,
ClientStreamingCallTryCancelAfterProcessing) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerTryCancelRequest,
std::to_string(grpc::testing::CANCEL_AFTER_PROCESSING));
grpc::testing::EchoResponse response;
std::unique_ptr<grpc::ClientWriter<grpc::testing::EchoRequest>> writer =
stub->RequestStream(&context, &response);
constexpr size_t kClientStreamingCounts = 100;
for (size_t i = 0; i < kClientStreamingCounts; ++i) {
grpc::testing::EchoRequest request;
request.set_message("ClientStreamingCallAfterProcessing" +
std::to_string(i));
writer->Write(request);
}
writer->WritesDone();
grpc::Status status = writer->Finish();
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.error_code(), grpc::StatusCode::CANCELLED);
}
TEST_P(End2EndBinderTransportTest, BiDirStreamingCall) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
grpc::ClientContext context;
std::shared_ptr<grpc::ClientReaderWriter<grpc::testing::EchoRequest,
grpc::testing::EchoResponse>>
stream = stub->BidiStream(&context);
constexpr size_t kBiDirStreamingCounts = 100;
struct WriterArgs {
std::shared_ptr<grpc::ClientReaderWriter<grpc::testing::EchoRequest,
grpc::testing::EchoResponse>>
stream;
size_t bi_dir_streaming_counts;
} writer_args;
writer_args.stream = stream;
writer_args.bi_dir_streaming_counts = kBiDirStreamingCounts;
auto writer_fn = [](void* arg) {
const WriterArgs& args = *static_cast<WriterArgs*>(arg);
for (size_t i = 0; i < args.bi_dir_streaming_counts; ++i) {
grpc::testing::EchoRequest request;
request.set_message("BiDirStreamingCall" + std::to_string(i));
args.stream->Write(request);
}
args.stream->WritesDone();
};
grpc_core::Thread writer_thread("writer-thread", writer_fn,
static_cast<void*>(&writer_args));
writer_thread.Start();
for (size_t i = 0; i < kBiDirStreamingCounts; ++i) {
grpc::testing::EchoResponse response;
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(response.message(), "BiDirStreamingCall" + std::to_string(i));
}
grpc::Status status = stream->Finish();
EXPECT_TRUE(status.ok());
writer_thread.Join();
}
// Disabled because the test case is ~0.01% flaky
TEST_P(End2EndBinderTransportTest,
DISABLED_BiDirStreamingCallServerFinishesHalfway) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
constexpr size_t kBiDirStreamingCounts = 100;
grpc::ClientContext context;
context.AddMetadata(grpc::testing::kServerFinishAfterNReads,
std::to_string(kBiDirStreamingCounts / 2));
std::shared_ptr<grpc::ClientReaderWriter<grpc::testing::EchoRequest,
grpc::testing::EchoResponse>>
stream = stub->BidiStream(&context);
struct WriterArgs {
std::shared_ptr<grpc::ClientReaderWriter<grpc::testing::EchoRequest,
grpc::testing::EchoResponse>>
stream;
size_t bi_dir_streaming_counts;
} writer_args;
writer_args.stream = stream;
writer_args.bi_dir_streaming_counts = kBiDirStreamingCounts;
auto writer_fn = [](void* arg) {
const WriterArgs& args = *static_cast<WriterArgs*>(arg);
for (size_t i = 0; i < args.bi_dir_streaming_counts; ++i) {
grpc::testing::EchoRequest request;
request.set_message("BiDirStreamingCallServerFinishesHalfway" +
std::to_string(i));
if (!args.stream->Write(request)) {
return;
}
}
args.stream->WritesDone();
};
grpc_core::Thread writer_thread("writer-thread", writer_fn,
static_cast<void*>(&writer_args));
writer_thread.Start();
for (size_t i = 0; i < kBiDirStreamingCounts / 2; ++i) {
grpc::testing::EchoResponse response;
EXPECT_TRUE(stream->Read(&response));
EXPECT_EQ(response.message(),
"BiDirStreamingCallServerFinishesHalfway" + std::to_string(i));
}
grpc::testing::EchoResponse response;
EXPECT_FALSE(stream->Read(&response));
writer_thread.Join();
grpc::Status status = stream->Finish();
EXPECT_TRUE(status.ok());
}
TEST_P(End2EndBinderTransportTest, LargeMessages) {
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub = NewStub();
for (size_t size = 1; size <= 1024 * 1024; size *= 4) {
grpc::ClientContext context;
grpc::testing::EchoRequest request;
grpc::testing::EchoResponse response;
request.set_message(std::string(size, 'a'));
grpc::Status status = stub->Echo(&context, request, &response);
EXPECT_TRUE(status.ok());
EXPECT_EQ(response.message().size(), size);
EXPECT_TRUE(std::all_of(response.message().begin(),
response.message().end(),
[](char c) { return c == 'a'; }));
}
}
INSTANTIATE_TEST_SUITE_P(End2EndBinderTransportTestWithDifferentDelayTimes,
End2EndBinderTransportTest,
testing::Values(absl::ZeroDuration(),
absl::Microseconds(10),
absl::Milliseconds(10)));
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1,276 +0,0 @@
// 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 "test/core/transport/binder/end2end/fake_binder.h"
#include <string>
#include <utility>
#include "absl/log/log.h"
#include "src/core/util/crash.h"
namespace grpc_binder {
namespace end2end_testing {
TransactionProcessor* g_transaction_processor = nullptr;
int32_t FakeWritableParcel::GetDataSize() const { return data_size_; }
absl::Status FakeWritableParcel::WriteInt32(int32_t data) {
data_.push_back(data);
data_size_ += sizeof(int32_t);
return absl::OkStatus();
}
absl::Status FakeWritableParcel::WriteInt64(int64_t data) {
data_.push_back(data);
data_size_ += sizeof(int64_t);
return absl::OkStatus();
}
absl::Status FakeWritableParcel::WriteBinder(HasRawBinder* binder) {
data_.push_back(binder->GetRawBinder());
data_size_ += sizeof(void*);
return absl::OkStatus();
}
absl::Status FakeWritableParcel::WriteString(absl::string_view s) {
data_.push_back(std::string(s));
data_size_ += s.size();
return absl::OkStatus();
}
absl::Status FakeWritableParcel::WriteByteArray(const int8_t* buffer,
int32_t length) {
data_.push_back(std::vector<int8_t>(buffer, buffer + length));
data_size_ += length;
return absl::OkStatus();
}
int32_t FakeReadableParcel::GetDataSize() const { return data_size_; }
absl::Status FakeReadableParcel::ReadInt32(int32_t* data) {
if (data_position_ >= data_.size() ||
!absl::holds_alternative<int32_t>(data_[data_position_])) {
return absl::InternalError("ReadInt32 failed");
}
*data = absl::get<int32_t>(data_[data_position_++]);
return absl::OkStatus();
}
absl::Status FakeReadableParcel::ReadInt64(int64_t* data) {
if (data_position_ >= data_.size() ||
!absl::holds_alternative<int64_t>(data_[data_position_])) {
return absl::InternalError("ReadInt64 failed");
}
*data = absl::get<int64_t>(data_[data_position_++]);
return absl::OkStatus();
}
absl::Status FakeReadableParcel::ReadBinder(std::unique_ptr<Binder>* data) {
if (data_position_ >= data_.size() ||
!absl::holds_alternative<void*>(data_[data_position_])) {
return absl::InternalError("ReadBinder failed");
}
void* endpoint = absl::get<void*>(data_[data_position_++]);
if (!endpoint) return absl::InternalError("ReadBinder failed");
*data = std::make_unique<FakeBinder>(static_cast<FakeEndpoint*>(endpoint));
return absl::OkStatus();
}
absl::Status FakeReadableParcel::ReadString(std::string* str) {
if (data_position_ >= data_.size() ||
!absl::holds_alternative<std::string>(data_[data_position_])) {
return absl::InternalError("ReadString failed");
}
*str = absl::get<std::string>(data_[data_position_++]);
return absl::OkStatus();
}
absl::Status FakeReadableParcel::ReadByteArray(std::string* data) {
if (data_position_ >= data_.size() ||
!absl::holds_alternative<std::vector<int8_t>>(data_[data_position_])) {
return absl::InternalError("ReadByteArray failed");
}
const std::vector<int8_t>& byte_array =
absl::get<std::vector<int8_t>>(data_[data_position_++]);
data->resize(byte_array.size());
for (size_t i = 0; i < byte_array.size(); ++i) {
(*data)[i] = byte_array[i];
}
return absl::OkStatus();
}
absl::Status FakeBinder::Transact(BinderTransportTxCode tx_code) {
endpoint_->tunnel->EnQueueTransaction(endpoint_->other_end, tx_code,
input_->MoveData());
return absl::OkStatus();
}
FakeTransactionReceiver::FakeTransactionReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb transact_cb) {
persistent_tx_receiver_ = &g_transaction_processor->NewPersistentTxReceiver(
std::move(wire_reader_ref), std::move(transact_cb),
std::make_unique<FakeBinderTunnel>());
}
std::unique_ptr<TransactionReceiver> FakeBinder::ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb) const {
return std::make_unique<FakeTransactionReceiver>(wire_reader_ref, cb);
}
void* FakeTransactionReceiver::GetRawBinder() {
return persistent_tx_receiver_->tunnel_->GetSendEndpoint();
}
std::unique_ptr<Binder> FakeTransactionReceiver::GetSender() const {
return std::make_unique<FakeBinder>(
persistent_tx_receiver_->tunnel_->GetSendEndpoint());
}
PersistentFakeTransactionReceiver::PersistentFakeTransactionReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb,
std::unique_ptr<FakeBinderTunnel> tunnel)
: wire_reader_ref_(std::move(wire_reader_ref)),
callback_(std::move(cb)),
tunnel_(std::move(tunnel)) {
FakeEndpoint* recv_endpoint = tunnel_->GetRecvEndpoint();
recv_endpoint->owner = this;
}
TransactionProcessor::TransactionProcessor(absl::Duration delay)
: delay_nsec_(absl::ToInt64Nanoseconds(delay)),
tx_thread_(
"process-thread",
[](void* arg) {
grpc_core::ExecCtx exec_ctx;
auto* self = static_cast<TransactionProcessor*>(arg);
self->ProcessLoop();
},
this),
terminated_(false) {
tx_thread_.Start();
}
void TransactionProcessor::SetDelay(absl::Duration delay) {
delay_nsec_ = absl::ToInt64Nanoseconds(delay);
}
void TransactionProcessor::Terminate() {
if (!terminated_.load(std::memory_order_seq_cst)) {
LOG(INFO) << "Terminating the processor";
terminated_.store(true, std::memory_order_seq_cst);
tx_thread_.Join();
LOG(INFO) << "Processor terminated";
}
}
void TransactionProcessor::WaitForNextTransaction() {
absl::Time now = absl::Now();
if (now < deliver_time_) {
absl::Duration diff = deliver_time_ - now;
// Release the lock before going to sleep.
mu_.Unlock();
absl::SleepFor(diff);
mu_.Lock();
}
}
void TransactionProcessor::Flush() {
while (true) {
FakeEndpoint* target = nullptr;
BinderTransportTxCode tx_code{};
FakeData data;
mu_.Lock();
if (tx_queue_.empty()) {
mu_.Unlock();
break;
}
WaitForNextTransaction();
std::tie(target, tx_code, data) = std::move(tx_queue_.front());
tx_queue_.pop();
if (!tx_queue_.empty()) {
deliver_time_ = absl::Now() + GetRandomDelay();
}
mu_.Unlock();
auto* tx_receiver =
static_cast<PersistentFakeTransactionReceiver*>(target->owner);
auto parcel = std::make_unique<FakeReadableParcel>(std::move(data));
tx_receiver->Receive(tx_code, parcel.get()).IgnoreError();
}
}
void TransactionProcessor::ProcessLoop() {
while (!terminated_.load(std::memory_order_seq_cst)) {
FakeEndpoint* target = nullptr;
BinderTransportTxCode tx_code{};
FakeData data;
mu_.Lock();
if (tx_queue_.empty()) {
mu_.Unlock();
continue;
}
WaitForNextTransaction();
std::tie(target, tx_code, data) = std::move(tx_queue_.front());
tx_queue_.pop();
if (!tx_queue_.empty()) {
deliver_time_ = absl::Now() + GetRandomDelay();
}
mu_.Unlock();
auto* tx_receiver =
static_cast<PersistentFakeTransactionReceiver*>(target->owner);
auto parcel = std::make_unique<FakeReadableParcel>(std::move(data));
tx_receiver->Receive(tx_code, parcel.get()).IgnoreError();
grpc_core::ExecCtx::Get()->Flush();
}
Flush();
}
absl::Duration TransactionProcessor::GetRandomDelay() {
int64_t delay =
absl::Uniform<int64_t>(bit_gen_, delay_nsec_ / 2, delay_nsec_);
return absl::Nanoseconds(delay);
}
void TransactionProcessor::EnQueueTransaction(FakeEndpoint* target,
BinderTransportTxCode tx_code,
FakeData data) {
grpc_core::MutexLock lock(&mu_);
if (tx_queue_.empty()) {
// This is the first transaction in the queue. Compute its deliver time.
deliver_time_ = absl::Now() + GetRandomDelay();
}
tx_queue_.emplace(target, tx_code, std::move(data));
}
FakeBinderTunnel::FakeBinderTunnel()
: send_endpoint_(std::make_unique<FakeEndpoint>(this)),
recv_endpoint_(std::make_unique<FakeEndpoint>(this)) {
send_endpoint_->other_end = recv_endpoint_.get();
recv_endpoint_->other_end = send_endpoint_.get();
}
std::pair<std::unique_ptr<Binder>, std::unique_ptr<TransactionReceiver>>
NewBinderPair(TransactionReceiver::OnTransactCb transact_cb) {
auto tx_receiver = std::make_unique<FakeTransactionReceiver>(
nullptr, std::move(transact_cb));
std::unique_ptr<Binder> sender = tx_receiver->GetSender();
return std::make_pair(std::move(sender), std::move(tx_receiver));
}
} // namespace end2end_testing
} // namespace grpc_binder

@ -1,307 +0,0 @@
// 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.
// A collection of fake objects that offers in-memory simulation of data
// transmission from one binder to another.
//
// Once the implementation of Binder is changed from BinderAndroid to
// FakeBinder, we'll be able to test and fuzz our end-to-end binder transport in
// a non-Android environment.
//
// The following diagram shows the high-level overview of how the in-memory
// simulation works (FakeReceiver means FakeTransactionReceiver).
//
// thread boundary
// |
// |
// ---------------- ---------------- | receive
// | FakeBinder | | FakeReceiver | <--|----------------
// ---------------- ---------------- | |
// | ^ | ------------------------
// | endpoint owner | | | TransactionProcessor |
// | | | ------------------------
// v | | ^
// ---------------- ---------------- | |
// | FakeEndpoint | --------> | FakeEndpoint | ---|----------------
// ---------------- other_end ---------------- | enqueue
// | ^ ^ | |
// | | recv_endpoint | | |
// | | | |
// | | send_endpoint | |
// v | | v
// -------------------------------------------
// | FakeBinderTunnel |
// -------------------------------------------
#ifndef GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FAKE_BINDER_H
#define GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FAKE_BINDER_H
#include <atomic>
#include <forward_list>
#include <memory>
#include <queue>
#include <string>
#include <thread>
#include <tuple>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/random/random.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "absl/types/variant.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
#include "src/core/util/sync.h"
#include "src/core/util/thd.h"
namespace grpc_binder {
namespace end2end_testing {
using FakeData = std::vector<
absl::variant<int32_t, int64_t, void*, std::string, std::vector<int8_t>>>;
// A fake writable parcel.
//
// It simulates the functionalities of a real writable parcel and stores all
// written data in memory. The data can then be transferred by calling
// MoveData().
class FakeWritableParcel final : public WritableParcel {
public:
int32_t GetDataSize() const override;
absl::Status WriteInt32(int32_t data) override;
absl::Status WriteInt64(int64_t data) override;
absl::Status WriteBinder(HasRawBinder* binder) override;
absl::Status WriteString(absl::string_view s) override;
absl::Status WriteByteArray(const int8_t* buffer, int32_t length) override;
FakeData MoveData() { return std::move(data_); }
private:
FakeData data_;
int32_t data_size_ = 0;
};
// A fake readable parcel.
//
// It takes in the data transferred from a FakeWritableParcel and provides
// methods to retrieve those data in the receiving end.
class FakeReadableParcel final : public ReadableParcel {
public:
explicit FakeReadableParcel(FakeData data) : data_(std::move(data)) {
for (auto& d : data_) {
if (absl::holds_alternative<int32_t>(d)) {
data_size_ += sizeof(int32_t);
} else if (absl::holds_alternative<int64_t>(d)) {
data_size_ += sizeof(int64_t);
} else if (absl::holds_alternative<void*>(d)) {
data_size_ += sizeof(void*);
} else if (absl::holds_alternative<std::string>(d)) {
data_size_ += absl::get<std::string>(d).size();
} else {
data_size_ += absl::get<std::vector<int8_t>>(d).size();
}
}
}
int32_t GetDataSize() const override;
absl::Status ReadInt32(int32_t* data) override;
absl::Status ReadInt64(int64_t* data) override;
absl::Status ReadBinder(std::unique_ptr<Binder>* data) override;
absl::Status ReadByteArray(std::string* data) override;
absl::Status ReadString(std::string* str) override;
private:
const FakeData data_;
size_t data_position_ = 0;
int32_t data_size_ = 0;
};
class FakeBinder;
class FakeBinderTunnel;
// FakeEndpoint is a simple struct that holds the pointer to the other end, a
// pointer to the tunnel and a pointer to its owner. This tells the owner where
// the data should be sent.
struct FakeEndpoint {
explicit FakeEndpoint(FakeBinderTunnel* tunnel) : tunnel(tunnel) {}
FakeEndpoint* other_end;
FakeBinderTunnel* tunnel;
// The owner is either a FakeBinder (the sending part) or a
// FakeTransactionReceiver (the receiving part). Both parts hold an endpoint
// with |owner| pointing back to them and |other_end| pointing to each other.
void* owner;
};
class PersistentFakeTransactionReceiver;
// A fake transaction receiver.
//
// This is the receiving part of a pair of binders. When constructed, a binder
// tunnle is created, and the sending part can be retrieved by calling
// GetSender().
//
// It also provides a Receive() function to simulate the on-transaction
// callback of a real Android binder.
class FakeTransactionReceiver : public TransactionReceiver {
public:
FakeTransactionReceiver(grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb);
void* GetRawBinder() override;
std::unique_ptr<Binder> GetSender() const;
private:
PersistentFakeTransactionReceiver* persistent_tx_receiver_;
};
// A "persistent" version of the FakeTransactionReceiver. That is, its lifetime
// is managed by the processor and it outlives the wire reader and
// grpc_binder_transport, so we can safely dereference a pointer to it in
// ProcessLoop().
class PersistentFakeTransactionReceiver {
public:
PersistentFakeTransactionReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb,
std::unique_ptr<FakeBinderTunnel> tunnel);
absl::Status Receive(BinderTransportTxCode tx_code, ReadableParcel* parcel) {
return callback_(static_cast<transaction_code_t>(tx_code), parcel,
/*uid=*/0);
}
private:
grpc_core::RefCountedPtr<WireReader> wire_reader_ref_;
TransactionReceiver::OnTransactCb callback_;
std::unique_ptr<FakeBinderTunnel> tunnel_;
friend class FakeTransactionReceiver;
};
// The sending part of a binders pair. It provides a FakeWritableParcel to the
// user, and when Transact() is called, it transfers the written data to the
// other end of the tunnel by following the information in its endpoint.
class FakeBinder final : public Binder {
public:
explicit FakeBinder(FakeEndpoint* endpoint) : endpoint_(endpoint) {}
void Initialize() override {}
absl::Status PrepareTransaction() override {
input_ = std::make_unique<FakeWritableParcel>();
return absl::OkStatus();
}
absl::Status Transact(BinderTransportTxCode tx_code) override;
WritableParcel* GetWritableParcel() const override { return input_.get(); }
std::unique_ptr<TransactionReceiver> ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb transact_cb) const override;
void* GetRawBinder() override { return endpoint_->other_end; }
private:
FakeEndpoint* endpoint_;
std::unique_ptr<FakeWritableParcel> input_;
};
// A transaction processor.
//
// Once constructed, it'll create a another thread that deliver in-coming
// transactions to their destinations.
class TransactionProcessor {
public:
explicit TransactionProcessor(absl::Duration delay = absl::ZeroDuration());
~TransactionProcessor() { Terminate(); }
void SetDelay(absl::Duration delay);
void Terminate();
void ProcessLoop();
void Flush();
// Issue a transaction with |target| pointing to the target endpoint. The
// transactions will be delivered in the same order they're issued, possibly
// with random delay to simulate real-world situation.
void EnQueueTransaction(FakeEndpoint* target, BinderTransportTxCode tx_code,
FakeData data);
PersistentFakeTransactionReceiver& NewPersistentTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb,
std::unique_ptr<FakeBinderTunnel> tunnel) {
grpc_core::MutexLock lock(&tx_receiver_mu_);
storage_.emplace_front(wire_reader_ref, cb, std::move(tunnel));
return storage_.front();
}
private:
absl::Duration GetRandomDelay();
void WaitForNextTransaction() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
grpc_core::Mutex mu_;
std::queue<std::tuple<FakeEndpoint*, BinderTransportTxCode, FakeData>>
tx_queue_ ABSL_GUARDED_BY(mu_);
absl::Time deliver_time_ ABSL_GUARDED_BY(mu_);
int64_t delay_nsec_;
absl::BitGen bit_gen_;
grpc_core::Thread tx_thread_;
std::atomic<bool> terminated_;
grpc_core::Mutex tx_receiver_mu_;
// Use forward_list to avoid invalid pointers resulted by reallocation in
// containers such as std::vector.
std::forward_list<PersistentFakeTransactionReceiver> storage_
ABSL_GUARDED_BY(tx_receiver_mu_);
};
// The global (shared) processor. Test suite should be responsible of
// creating/deleting it.
extern TransactionProcessor* g_transaction_processor;
// A binder tunnel.
//
// It is a simple helper that creates and links two endpoints.
class FakeBinderTunnel {
public:
FakeBinderTunnel();
void EnQueueTransaction(FakeEndpoint* target, BinderTransportTxCode tx_code,
FakeData data) {
g_transaction_processor->EnQueueTransaction(target, tx_code,
std::move(data));
}
FakeEndpoint* GetSendEndpoint() const { return send_endpoint_.get(); }
FakeEndpoint* GetRecvEndpoint() const { return recv_endpoint_.get(); }
private:
std::unique_ptr<FakeEndpoint> send_endpoint_;
std::unique_ptr<FakeEndpoint> recv_endpoint_;
};
// A helper function for constructing a pair of connected binders.
std::pair<std::unique_ptr<Binder>, std::unique_ptr<TransactionReceiver>>
NewBinderPair(TransactionReceiver::OnTransactCb transact_cb);
} // namespace end2end_testing
} // namespace grpc_binder
#endif // GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FAKE_BINDER_H

@ -1,349 +0,0 @@
// 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 "test/core/transport/binder/end2end/fake_binder.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <random>
#include <string>
#include <utility>
#include "absl/strings/str_format.h"
#include "absl/time/time.h"
#include "test/core/test_util/test_config.h"
namespace grpc_binder {
namespace end2end_testing {
namespace {
class FakeBinderTest : public ::testing::TestWithParam<absl::Duration> {
public:
FakeBinderTest() {
g_transaction_processor = new TransactionProcessor(GetParam());
}
~FakeBinderTest() override { delete g_transaction_processor; }
};
} // namespace
TEST_P(FakeBinderTest, SendInt32) {
constexpr int kValue = 0x1234;
constexpr int kTxCode = 0x4321;
int called = 0;
std::unique_ptr<Binder> sender;
std::unique_ptr<TransactionReceiver> tx_receiver;
std::tie(sender, tx_receiver) = NewBinderPair(
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
EXPECT_EQ(tx_code, kTxCode);
int value = 0;
EXPECT_TRUE(parcel->ReadInt32(&value).ok());
EXPECT_EQ(value, kValue);
called++;
return absl::OkStatus();
});
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel->WriteInt32(kValue).ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
g_transaction_processor->Terminate();
EXPECT_EQ(called, 1);
}
TEST_P(FakeBinderTest, SendString) {
constexpr char kValue[] = "example-string";
constexpr int kTxCode = 0x4321;
int called = 0;
std::unique_ptr<Binder> sender;
std::unique_ptr<TransactionReceiver> tx_receiver;
std::tie(sender, tx_receiver) = NewBinderPair(
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
EXPECT_EQ(tx_code, kTxCode);
std::string value;
EXPECT_TRUE(parcel->ReadString(&value).ok());
EXPECT_STREQ(value.c_str(), kValue);
called++;
return absl::OkStatus();
});
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel->WriteString(kValue).ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
g_transaction_processor->Terminate();
EXPECT_EQ(called, 1);
}
TEST_P(FakeBinderTest, SendByteArray) {
constexpr char kValue[] = "example-byte-array";
constexpr int kTxCode = 0x4321;
int called = 0;
std::unique_ptr<Binder> sender;
std::unique_ptr<TransactionReceiver> tx_receiver;
std::tie(sender, tx_receiver) = NewBinderPair(
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
EXPECT_EQ(tx_code, kTxCode);
std::string value;
EXPECT_TRUE(parcel->ReadByteArray(&value).ok());
EXPECT_EQ(value, kValue);
called++;
return absl::OkStatus();
});
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel
->WriteByteArray(reinterpret_cast<const int8_t*>(kValue),
strlen(kValue))
.ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
g_transaction_processor->Terminate();
EXPECT_EQ(called, 1);
}
TEST_P(FakeBinderTest, SendMultipleItems) {
constexpr char kByteArray[] = "example-byte-array";
constexpr char kString[] = "example-string";
constexpr int kValue = 0x1234;
constexpr int kTxCode = 0x4321;
int called = 0;
std::unique_ptr<Binder> sender;
std::unique_ptr<TransactionReceiver> tx_receiver;
std::tie(sender, tx_receiver) = NewBinderPair(
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
int value_result;
EXPECT_EQ(tx_code, kTxCode);
EXPECT_TRUE(parcel->ReadInt32(&value_result).ok());
EXPECT_EQ(value_result, kValue);
std::string byte_array_result;
EXPECT_TRUE(parcel->ReadByteArray(&byte_array_result).ok());
EXPECT_EQ(byte_array_result, kByteArray);
std::string string_result;
EXPECT_TRUE(parcel->ReadString(&string_result).ok());
EXPECT_STREQ(string_result.c_str(), kString);
called++;
return absl::OkStatus();
});
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel->WriteInt32(kValue).ok());
EXPECT_TRUE(parcel
->WriteByteArray(reinterpret_cast<const int8_t*>(kByteArray),
strlen(kByteArray))
.ok());
EXPECT_TRUE(parcel->WriteString(kString).ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
g_transaction_processor->Terminate();
EXPECT_EQ(called, 1);
}
TEST_P(FakeBinderTest, SendBinder) {
constexpr int kValue = 0x1234;
constexpr int kTxCode = 0x4321;
int called = 0;
std::unique_ptr<Binder> sender;
std::unique_ptr<TransactionReceiver> tx_receiver;
std::tie(sender, tx_receiver) = NewBinderPair(
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
EXPECT_EQ(tx_code, kTxCode);
std::unique_ptr<Binder> binder;
EXPECT_TRUE(parcel->ReadBinder(&binder).ok());
EXPECT_TRUE(binder->PrepareTransaction().ok());
WritableParcel* writable_parcel = binder->GetWritableParcel();
EXPECT_TRUE(writable_parcel->WriteInt32(kValue).ok());
EXPECT_TRUE(binder->Transact(BinderTransportTxCode(kTxCode + 1)).ok());
called++;
return absl::OkStatus();
});
int called2 = 0;
std::unique_ptr<TransactionReceiver> tx_receiver2 =
std::make_unique<FakeTransactionReceiver>(
nullptr,
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
int value;
EXPECT_TRUE(parcel->ReadInt32(&value).ok());
EXPECT_EQ(value, kValue);
EXPECT_EQ(tx_code, kTxCode + 1);
called2++;
return absl::OkStatus();
});
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel->WriteBinder(tx_receiver2.get()).ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
g_transaction_processor->Terminate();
EXPECT_EQ(called, 1);
EXPECT_EQ(called2, 1);
}
TEST_P(FakeBinderTest, SendTransactionAfterDestruction) {
constexpr int kValue = 0x1234;
constexpr int kTxCode = 0x4321;
std::unique_ptr<Binder> sender;
int called = 0;
{
std::unique_ptr<TransactionReceiver> tx_receiver;
std::tie(sender, tx_receiver) = NewBinderPair(
[&](transaction_code_t tx_code, ReadableParcel* parcel, int /*uid*/) {
EXPECT_EQ(tx_code, kTxCode);
int value;
EXPECT_TRUE(parcel->ReadInt32(&value).ok());
EXPECT_EQ(value, kValue + called);
called++;
return absl::OkStatus();
});
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel->WriteInt32(kValue).ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
}
// tx_receiver gets destructed here. This additional transaction should
// *still* be received.
EXPECT_TRUE(sender->PrepareTransaction().ok());
WritableParcel* parcel = sender->GetWritableParcel();
EXPECT_TRUE(parcel->WriteInt32(kValue + 1).ok());
EXPECT_TRUE(sender->Transact(BinderTransportTxCode(kTxCode)).ok());
g_transaction_processor->Terminate();
EXPECT_EQ(called, 2);
}
namespace {
struct ThreadArgument {
int tid;
std::vector<std::vector<std::pair<std::unique_ptr<Binder>,
std::unique_ptr<TransactionReceiver>>>>*
global_binder_pairs;
std::vector<std::vector<int>>* global_cnts;
int tx_code;
int num_pairs_per_thread;
int num_transactions_per_pair;
grpc_core::Mutex* mu;
};
} // namespace
// Verify that this system works correctly in a concurrent environment.
//
// In end-to-end tests, there will be at least two threads, one from client to
// server and vice versa. Thus, it's important for us to make sure that the
// simulation is correct in such setup.
TEST_P(FakeBinderTest, StressTest) {
constexpr int kTxCode = 0x4321;
constexpr int kNumThreads = 16;
constexpr int kNumPairsPerThread = 128;
constexpr int kNumTransactionsPerPair = 128;
std::vector<ThreadArgument> args(kNumThreads);
grpc_core::Mutex mu;
std::vector<std::vector<
std::pair<std::unique_ptr<Binder>, std::unique_ptr<TransactionReceiver>>>>
global_binder_pairs(kNumThreads);
std::vector<std::vector<int>> global_cnts(
kNumThreads, std::vector<int>(kNumPairsPerThread, 0));
auto th_function = [](void* arg) {
ThreadArgument* th_arg = static_cast<ThreadArgument*>(arg);
int tid = th_arg->tid;
std::vector<std::pair<std::unique_ptr<Binder>,
std::unique_ptr<TransactionReceiver>>>
binder_pairs;
for (int p = 0; p < th_arg->num_pairs_per_thread; ++p) {
std::unique_ptr<Binder> binder;
std::unique_ptr<TransactionReceiver> tx_receiver;
int expected_tx_code = th_arg->tx_code;
std::vector<std::vector<int>>* cnt = th_arg->global_cnts;
std::tie(binder, tx_receiver) =
NewBinderPair([tid, p, cnt, expected_tx_code](
transaction_code_t tx_code, ReadableParcel* parcel,
int /*uid*/) mutable {
EXPECT_EQ(tx_code, expected_tx_code);
int value;
EXPECT_TRUE(parcel->ReadInt32(&value).ok());
EXPECT_EQ(tid, value);
EXPECT_TRUE(parcel->ReadInt32(&value).ok());
EXPECT_EQ(p, value);
EXPECT_TRUE(parcel->ReadInt32(&value).ok());
EXPECT_EQ((*cnt)[tid][p], value);
(*cnt)[tid][p]++;
return absl::OkStatus();
});
binder_pairs.emplace_back(std::move(binder), std::move(tx_receiver));
}
std::vector<int> order;
for (int i = 0; i < th_arg->num_pairs_per_thread; ++i) {
for (int j = 0; j < th_arg->num_transactions_per_pair; ++j) {
order.emplace_back(i);
}
}
std::mt19937 rng(tid);
std::shuffle(order.begin(), order.end(), rng);
std::vector<int> tx_cnt(th_arg->num_pairs_per_thread);
for (int p : order) {
EXPECT_TRUE(binder_pairs[p].first->PrepareTransaction().ok());
WritableParcel* parcel = binder_pairs[p].first->GetWritableParcel();
EXPECT_TRUE(parcel->WriteInt32(th_arg->tid).ok());
EXPECT_TRUE(parcel->WriteInt32(p).ok());
EXPECT_TRUE(parcel->WriteInt32(tx_cnt[p]++).ok());
EXPECT_TRUE(binder_pairs[p]
.first->Transact(BinderTransportTxCode(th_arg->tx_code))
.ok());
}
th_arg->mu->Lock();
(*th_arg->global_binder_pairs)[tid] = std::move(binder_pairs);
th_arg->mu->Unlock();
};
std::vector<grpc_core::Thread> thrs(kNumThreads);
std::vector<std::string> thr_names(kNumThreads);
for (int i = 0; i < kNumThreads; ++i) {
args[i].tid = i;
args[i].global_binder_pairs = &global_binder_pairs;
args[i].global_cnts = &global_cnts;
args[i].tx_code = kTxCode;
args[i].num_pairs_per_thread = kNumPairsPerThread;
args[i].num_transactions_per_pair = kNumTransactionsPerPair;
args[i].mu = &mu;
thr_names[i] = absl::StrFormat("thread-%d", i);
thrs[i] = grpc_core::Thread(thr_names[i].c_str(), th_function, &args[i]);
}
for (auto& th : thrs) th.Start();
for (auto& th : thrs) th.Join();
g_transaction_processor->Terminate();
}
INSTANTIATE_TEST_SUITE_P(FakeBinderTestWithDifferentDelayTimes, FakeBinderTest,
testing::Values(absl::ZeroDuration(),
absl::Nanoseconds(10),
absl::Microseconds(10)));
} // namespace end2end_testing
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1,101 +0,0 @@
# 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", "grpc_package", "grpc_proto_library")
load("//test/core/test_util:grpc_fuzzer.bzl", "grpc_proto_fuzzer")
grpc_package(
name = "test/core/transport/binder/end2end/fuzzers",
features = [
"layering_check",
],
)
licenses(["notice"])
# Protobuf messages for generating inputs. We manually define proto
# library rule here so the same proto file can be shared between multiple
# grpc_proto_fuzzer targets
grpc_proto_library(
name = "binder_transport_fuzzer_proto",
srcs = ["binder_transport_fuzzer.proto"],
)
grpc_cc_library(
name = "fuzzer_utils",
srcs = ["fuzzer_utils.cc"],
external_deps = [
"absl/log:check",
"absl/log:log",
],
language = "c++",
public_hdrs = ["fuzzer_utils.h"],
deps = [
"binder_transport_fuzzer_proto",
"//:gpr",
"//:grpc++",
"//:grpc++_base",
"//:grpc_base",
"//test/core/test_util:grpc_test_util",
],
)
grpc_proto_fuzzer(
name = "binder_transport_client_fuzzer",
srcs = [
"client_fuzzer.cc",
],
corpus = "binder_transport_client_fuzzer_corpus",
external_deps = ["absl/log:check"],
owner = "binder",
proto = "client.proto",
tags = [
"no_mac",
"no_windows",
],
deps = [
"binder_transport_fuzzer_proto",
":fuzzer_utils",
"//:gpr",
"//:grpc++",
"//:grpc++_base",
"//:grpc_base",
"//test/core/test_util:grpc_test_util",
],
)
grpc_proto_fuzzer(
name = "binder_transport_server_fuzzer",
srcs = [
"server_fuzzer.cc",
],
corpus = "binder_transport_server_fuzzer_corpus",
external_deps = ["absl/log:check"],
owner = "binder",
proto = "server.proto",
tags = [
"no_mac",
"no_windows",
],
deps = [
"binder_transport_fuzzer_proto",
":fuzzer_utils",
"//:gpr",
"//:grpc++",
"//:grpc++_base",
"//:grpc_base",
"//src/core:slice",
"//test/core/test_util:grpc_test_util",
],
)

@ -1,81 +0,0 @@
// 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.
syntax = "proto3";
package binder_transport_fuzzer;
message Binder {}
message Value {
oneof data_type {
int32 i32 = 1;
int64 i64 = 2;
bytes byte_array = 3;
// Strings in Parcel could also contain non UTF-8 data so we use bytes
// to represent string here
bytes str = 4;
Binder binder = 5;
}
}
message Parcel {
repeated Value values = 1;
// Simulates the return value of AParcel_getDataSize
// (The value generated by protobuf libprotobuf-mutator might not always make sense
// but the transport implementation should handle that)
int32 data_size = 2;
}
enum TransactionCode {
INVALID = 0;
SETUP_TRANSPORT = 1;
SHUTDOWN_TRANSPORT = 2;
ACKNOWLEDGE_BYTES = 3;
PING = 4;
PING_RESPONSE = 5;
}
message Transaction {
TransactionCode code = 1;
int32 uid = 2;
Parcel parcel = 3;
}
// Special parcel that used for setting up transport.
// TODO(mingcl): Consider also fuzzing the setup transport code path
message SetupTransportParcel {
int32 version = 1;
// Simulates the return value of AParcel_getDataSize
// (The value generated by protobuf libprotobuf-mutator might not always make sense
// but the transport implementation should handle that)
int32 data_size = 2;
}
message SetupTransportTransaction {
int32 uid = 1;
SetupTransportParcel parcel = 2;
}
message IncomingParcels {
SetupTransportTransaction setup_transport_transaction = 1;
repeated Transaction transactions = 2;
}
message Input {
IncomingParcels incoming_parcels = 1;
}

@ -1,17 +0,0 @@
// 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.
syntax = "proto3";
package binder_transport_fuzzer;

@ -1,158 +0,0 @@
// 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 <grpc/grpc.h>
#include <grpcpp/security/binder_security_policy.h>
#include <thread>
#include <utility>
#include "absl/log/check.h"
#include "absl/memory/memory.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/channel_create.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/end2end/fuzzers/binder_transport_fuzzer.pb.h"
#include "test/core/transport/binder/end2end/fuzzers/fuzzer_utils.h"
bool squelch = true;
bool leak_check = true;
static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
if (squelch) {
grpc_disable_all_absl_logs();
}
grpc_init();
{
// Copied and modified from grpc/test/core/end2end/fuzzers/client_fuzzer.cc
grpc_core::ExecCtx exec_ctx;
grpc_core::Executor::SetThreadingAll(false);
grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
grpc_core::Transport* client_transport =
grpc_create_binder_transport_client(
std::make_unique<grpc_binder::fuzzing::BinderForFuzzing>(
input.incoming_parcels()),
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>());
grpc_arg authority_arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_ARG_DEFAULT_AUTHORITY),
const_cast<char*>("test-authority"));
grpc_channel_args* args =
grpc_channel_args_copy_and_add(nullptr, &authority_arg, 1);
auto channel_args = grpc_core::CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(args);
auto channel =
grpc_core::ChannelCreate("test-target", channel_args,
GRPC_CLIENT_DIRECT_CHANNEL, client_transport)
->release()
->c_ptr();
grpc_channel_args_destroy(args);
grpc_slice host = grpc_slice_from_static_string("localhost");
grpc_call* call = grpc_channel_create_call(
channel, nullptr, 0, cq, grpc_slice_from_static_string("/foo"), &host,
gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
grpc_metadata_array initial_metadata_recv;
grpc_metadata_array_init(&initial_metadata_recv);
grpc_byte_buffer* response_payload_recv = nullptr;
grpc_metadata_array trailing_metadata_recv;
grpc_metadata_array_init(&trailing_metadata_recv);
grpc_status_code status;
grpc_slice details = grpc_empty_slice();
grpc_op ops[6];
memset(ops, 0, sizeof(ops));
grpc_op* op = ops;
op->op = GRPC_OP_SEND_INITIAL_METADATA;
op->data.send_initial_metadata.count = 0;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_INITIAL_METADATA;
op->data.recv_initial_metadata.recv_initial_metadata =
&initial_metadata_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_MESSAGE;
op->data.recv_message.recv_message = &response_payload_recv;
op->flags = 0;
op->reserved = nullptr;
op++;
op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
op->data.recv_status_on_client.status = &status;
op->data.recv_status_on_client.status_details = &details;
op->flags = 0;
op->reserved = nullptr;
op++;
grpc_call_error error = grpc_call_start_batch(
call, ops, static_cast<size_t>(op - ops), tag(1), nullptr);
int requested_calls = 1;
CHECK_EQ(error, GRPC_CALL_OK);
grpc_event ev;
while (true) {
grpc_core::ExecCtx::Get()->Flush();
ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
nullptr);
switch (ev.type) {
case GRPC_QUEUE_TIMEOUT:
goto done;
case GRPC_QUEUE_SHUTDOWN:
break;
case GRPC_OP_COMPLETE:
requested_calls--;
break;
}
}
done:
if (requested_calls) {
grpc_call_cancel(call, nullptr);
}
grpc_binder::fuzzing::JoinFuzzingThread();
for (int i = 0; i < requested_calls; i++) {
ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
nullptr);
CHECK(ev.type == GRPC_OP_COMPLETE);
}
grpc_completion_queue_shutdown(cq);
for (int i = 0; i < requested_calls; i++) {
ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
nullptr);
CHECK(ev.type == GRPC_QUEUE_SHUTDOWN);
}
grpc_call_unref(call);
grpc_completion_queue_destroy(cq);
grpc_metadata_array_destroy(&initial_metadata_recv);
grpc_metadata_array_destroy(&trailing_metadata_recv);
grpc_slice_unref(details);
grpc_channel_destroy(channel);
if (response_payload_recv != nullptr) {
grpc_byte_buffer_destroy(response_payload_recv);
}
}
grpc_shutdown();
}

@ -1,157 +0,0 @@
// 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 "test/core/transport/binder/end2end/fuzzers/fuzzer_utils.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
namespace grpc_binder {
namespace fuzzing {
namespace {
std::thread* g_fuzzing_thread = nullptr;
template <typename... Args>
void CreateFuzzingThread(Args&&... args) {
CHECK_EQ(g_fuzzing_thread, nullptr);
g_fuzzing_thread = new std::thread(std::forward<Args>(args)...);
}
} // namespace
void JoinFuzzingThread() {
if (g_fuzzing_thread) {
g_fuzzing_thread->join();
delete g_fuzzing_thread;
g_fuzzing_thread = nullptr;
}
}
int32_t ReadableParcelForFuzzing::GetDataSize() const {
return parcel_data_size_;
}
absl::Status ReadableParcelForFuzzing::ReadInt32(int32_t* data) {
if (consumed_data_size_ >= kParcelDataSizeLimit) {
return absl::InternalError("Parcel size limit exceeds");
}
if (values_.empty() || !values_.front().has_i32()) {
return absl::InternalError("error");
}
*data = values_.front().i32();
values_.pop();
consumed_data_size_ += sizeof(int32_t);
return absl::OkStatus();
}
absl::Status ReadableParcelForFuzzing::ReadInt64(int64_t* data) {
if (consumed_data_size_ >= kParcelDataSizeLimit) {
return absl::InternalError("Parcel size limit exceeds");
}
if (values_.empty() || !values_.front().has_i64()) {
return absl::InternalError("error");
}
*data = values_.front().i64();
values_.pop();
consumed_data_size_ += sizeof(int64_t);
return absl::OkStatus();
}
absl::Status ReadableParcelForFuzzing::ReadBinder(
std::unique_ptr<Binder>* binder) {
if (consumed_data_size_ >= kParcelDataSizeLimit) {
return absl::InternalError("Parcel size limit exceeds");
}
if (values_.empty() || !values_.front().has_binder()) {
return absl::InternalError("error");
}
*binder = std::make_unique<BinderForFuzzing>();
values_.pop();
consumed_data_size_ += sizeof(void*);
return absl::OkStatus();
}
absl::Status ReadableParcelForFuzzing::ReadByteArray(std::string* data) {
if (consumed_data_size_ >= kParcelDataSizeLimit) {
return absl::InternalError("Parcel size limit exceeds");
}
if (values_.empty() || !values_.front().has_byte_array()) {
return absl::InternalError("error");
}
*data = values_.front().byte_array();
values_.pop();
consumed_data_size_ += data->size();
return absl::OkStatus();
}
absl::Status ReadableParcelForFuzzing::ReadString(std::string* data) {
if (consumed_data_size_ >= kParcelDataSizeLimit) {
return absl::InternalError("Parcel size limit exceeds");
}
if (values_.empty() || !values_.front().has_str()) {
return absl::InternalError("error");
}
*data = values_.front().str();
values_.pop();
consumed_data_size_ += data->size();
return absl::OkStatus();
}
void FuzzingLoop(
binder_transport_fuzzer::IncomingParcels incoming_parcels,
grpc_core::RefCountedPtr<grpc_binder::WireReader> wire_reader_ref,
grpc_binder::TransactionReceiver::OnTransactCb callback) {
{
// Send SETUP_TRANSPORT request.
std::unique_ptr<grpc_binder::ReadableParcel> parcel =
std::make_unique<ReadableParcelForFuzzing>(
incoming_parcels.setup_transport_transaction().parcel());
callback(static_cast<transaction_code_t>(
grpc_binder::BinderTransportTxCode::SETUP_TRANSPORT),
parcel.get(),
/*uid=*/incoming_parcels.setup_transport_transaction().uid())
.IgnoreError();
}
for (const auto& tx_iter : incoming_parcels.transactions()) {
transaction_code_t tx_code = tx_iter.code();
std::unique_ptr<grpc_binder::ReadableParcel> parcel =
std::make_unique<ReadableParcelForFuzzing>(tx_iter.parcel());
callback(tx_code, parcel.get(),
/*uid=*/tx_iter.uid())
.IgnoreError();
}
wire_reader_ref = nullptr;
}
TransactionReceiverForFuzzing::TransactionReceiverForFuzzing(
binder_transport_fuzzer::IncomingParcels incoming_parcels,
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb) {
LOG(INFO) << "Construct TransactionReceiverForFuzzing";
CreateFuzzingThread(FuzzingLoop, std::move(incoming_parcels),
std::move(wire_reader_ref), std::move(cb));
}
std::unique_ptr<TransactionReceiver> BinderForFuzzing::ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb) const {
auto tx_receiver = std::make_unique<TransactionReceiverForFuzzing>(
incoming_parcels_, wire_reader_ref, cb);
return tx_receiver;
}
} // namespace fuzzing
} // namespace grpc_binder

@ -1,152 +0,0 @@
// 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_TEST_CORE_TRANSPORT_BINDER_END2END_FUZZERS_FUZZER_UTILS_H
#define GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FUZZERS_FUZZER_UTILS_H
#include <memory>
#include <queue>
#include <string>
#include <thread>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
#include "src/core/util/crash.h"
#include "test/core/transport/binder/end2end/fuzzers/binder_transport_fuzzer.pb.h"
namespace grpc_binder {
namespace fuzzing {
// A WritableParcel implementation that simply does nothing. Don't use
// MockWritableParcel here since capturing calls is expensive.
class NoOpWritableParcel : public WritableParcel {
public:
int32_t GetDataSize() const override { return 0; }
absl::Status WriteInt32(int32_t /*data*/) override {
return absl::OkStatus();
}
absl::Status WriteInt64(int64_t /*data*/) override {
return absl::OkStatus();
}
absl::Status WriteBinder(HasRawBinder* /*binder*/) override {
return absl::OkStatus();
}
absl::Status WriteString(absl::string_view /*s*/) override {
return absl::OkStatus();
}
absl::Status WriteByteArray(const int8_t* /*buffer*/,
int32_t /*length*/) override {
return absl::OkStatus();
}
};
// Binder implementation used in fuzzing.
//
// Most of its the functionalities are no-op, except ConstructTxReceiver now
// returns a TransactionReceiverForFuzzing.
class BinderForFuzzing : public Binder {
public:
BinderForFuzzing() : input_(std::make_unique<NoOpWritableParcel>()) {}
explicit BinderForFuzzing(const binder_transport_fuzzer::IncomingParcels& p)
: incoming_parcels_(p), input_(std::make_unique<NoOpWritableParcel>()) {}
void Initialize() override {}
absl::Status PrepareTransaction() override { return absl::OkStatus(); }
absl::Status Transact(BinderTransportTxCode /*tx_code*/) override {
return absl::OkStatus();
}
std::unique_ptr<TransactionReceiver> ConstructTxReceiver(
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb) const override;
WritableParcel* GetWritableParcel() const override { return input_.get(); }
void* GetRawBinder() override { return nullptr; }
private:
binder_transport_fuzzer::IncomingParcels incoming_parcels_;
std::unique_ptr<WritableParcel> input_;
};
// ReadableParcel implementation used in fuzzing.
//
// It consumes a Parcel generated by mutator, and returns the data in the Parcel
// upon user's requests.
class ReadableParcelForFuzzing : public ReadableParcel {
public:
explicit ReadableParcelForFuzzing(const binder_transport_fuzzer::Parcel& p)
: parcel_data_size_(p.data_size()), consumed_data_size_(0) {
for (const auto& v : p.values()) {
values_.push(v);
}
}
// Construct from SetupTransportParcel, which have fixed types of data in it.
explicit ReadableParcelForFuzzing(
const binder_transport_fuzzer::SetupTransportParcel& p)
: parcel_data_size_(p.data_size()), consumed_data_size_(0) {
// Creates value for protocol version and put it into the queue
binder_transport_fuzzer::Value version_value;
version_value.set_i32(p.version());
values_.push(version_value);
// Creates a binder value and put it into the queue
binder_transport_fuzzer::Value binder_value;
binder_value.mutable_binder(); // sets one-of field
values_.push(binder_value);
}
int32_t GetDataSize() const override;
absl::Status ReadInt32(int32_t* data) override;
absl::Status ReadInt64(int64_t* data) override;
absl::Status ReadBinder(std::unique_ptr<Binder>* binder) override;
absl::Status ReadByteArray(std::string* data) override;
absl::Status ReadString(std::string* data) override;
private:
// Stores data/objects in binder in their order. Since we don't support random
// access using a std::queue is enough here.
std::queue<binder_transport_fuzzer::Value> values_;
const int32_t parcel_data_size_;
static constexpr size_t kParcelDataSizeLimit = 1024 * 1024;
size_t consumed_data_size_;
};
void JoinFuzzingThread();
// TransactionReceiver implementation used in fuzzing.
//
// When constructed, start sending fuzzed requests to the client. When all the
// bytes are consumed, the reference to WireReader will be released.
class TransactionReceiverForFuzzing : public TransactionReceiver {
public:
TransactionReceiverForFuzzing(
binder_transport_fuzzer::IncomingParcels incoming_parcels,
grpc_core::RefCountedPtr<WireReader> wire_reader_ref,
TransactionReceiver::OnTransactCb cb);
void* GetRawBinder() override { return nullptr; }
};
} // namespace fuzzing
} // namespace grpc_binder
#endif // GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_FUZZERS_FUZZER_UTILS_H

@ -1,17 +0,0 @@
// 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.
syntax = "proto3";
package binder_transport_fuzzer;

@ -1,132 +0,0 @@
// 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 <grpc/grpc.h>
#include "absl/log/check.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/server/server.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/end2end/fuzzers/binder_transport_fuzzer.pb.h"
#include "test/core/transport/binder/end2end/fuzzers/fuzzer_utils.h"
bool squelch = true;
bool leak_check = true;
static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }
DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
if (squelch) {
grpc_disable_all_absl_logs();
}
grpc_init();
{
// Copied and modified from grpc/test/core/end2end/fuzzers/server_fuzzer.cc
grpc_core::ExecCtx exec_ctx;
grpc_core::Executor::SetThreadingAll(false);
grpc_server* server = grpc_server_create(nullptr, nullptr);
grpc_completion_queue* cq = grpc_completion_queue_create_for_next(nullptr);
grpc_server_register_completion_queue(server, cq, nullptr);
// TODO(ctiller): add more registered methods (one for POST, one for PUT)
grpc_server_register_method(server, "/reg", nullptr, {}, 0);
grpc_server_start(server);
grpc_core::Transport* server_transport =
grpc_create_binder_transport_server(
std::make_unique<grpc_binder::fuzzing::BinderForFuzzing>(
input.incoming_parcels()),
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>());
grpc_core::ChannelArgs channel_args = grpc_core::CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(nullptr);
(void)grpc_core::Server::FromC(server)->SetupTransport(
server_transport, nullptr, channel_args, nullptr);
grpc_call* call1 = nullptr;
grpc_call_details call_details1;
grpc_metadata_array request_metadata1;
grpc_call_details_init(&call_details1);
grpc_metadata_array_init(&request_metadata1);
int requested_calls = 0;
CHECK(GRPC_CALL_OK ==
grpc_server_request_call(server, &call1, &call_details1,
&request_metadata1, cq, cq, tag(1)));
requested_calls++;
grpc_event ev;
while (true) {
grpc_core::ExecCtx::Get()->Flush();
ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
nullptr);
switch (ev.type) {
case GRPC_QUEUE_TIMEOUT:
goto done;
case GRPC_QUEUE_SHUTDOWN:
break;
case GRPC_OP_COMPLETE:
if (ev.tag == tag(1)) {
requested_calls--;
// TODO(ctiller): keep reading that call!
}
break;
}
}
done:
grpc_binder::fuzzing::JoinFuzzingThread();
if (call1 != nullptr) grpc_call_unref(call1);
grpc_call_details_destroy(&call_details1);
grpc_metadata_array_destroy(&request_metadata1);
grpc_server_shutdown_and_notify(server, cq, tag(0xdead));
grpc_server_cancel_all_calls(server);
grpc_core::Timestamp deadline =
grpc_core::Timestamp::Now() + grpc_core::Duration::Seconds(5);
for (int i = 0; i <= requested_calls; i++) {
// A single grpc_completion_queue_next might not be sufficient for getting
// the tag from shutdown, because we might potentially get blocked by
// an operation happening on the timer thread.
// For example, the deadline timer might expire, leading to the timer
// thread trying to cancel the RPC and thereby acquiring a few references
// to the call. This will prevent the shutdown to complete till the timer
// thread releases those references.
// As a solution, we are going to keep performing a cq_next for a
// liberal period of 5 seconds for the timer thread to complete its work.
do {
ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
nullptr);
grpc_core::ExecCtx::Get()->InvalidateNow();
} while (ev.type != GRPC_OP_COMPLETE &&
grpc_core::Timestamp::Now() < deadline);
CHECK(ev.type == GRPC_OP_COMPLETE);
}
grpc_completion_queue_shutdown(cq);
for (int i = 0; i <= requested_calls; i++) {
do {
ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
nullptr);
grpc_core::ExecCtx::Get()->InvalidateNow();
} while (ev.type != GRPC_QUEUE_SHUTDOWN &&
grpc_core::Timestamp::Now() < deadline);
CHECK(ev.type == GRPC_QUEUE_SHUTDOWN);
}
grpc_server_destroy(server);
grpc_completion_queue_destroy(cq);
}
grpc_shutdown();
}

@ -1,133 +0,0 @@
// 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 "test/core/transport/binder/end2end/testing_channel_create.h"
#include <grpcpp/security/binder_security_policy.h>
#include <utility>
#include "absl/log/check.h"
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader_impl.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/surface/channel.h"
#include "src/core/lib/surface/channel_create.h"
#include "src/core/lib/transport/error_utils.h"
namespace grpc_binder {
namespace end2end_testing {
namespace {
// Since we assume the first half of the transport setup is completed before the
// server side enters WireReader::SetupTransport, we need this helper to wait
// and finish that part of the negotiation for us.
class ServerSetupTransportHelper {
public:
ServerSetupTransportHelper()
: wire_reader_(std::make_unique<WireReaderImpl>(
/*transport_stream_receiver=*/nullptr, /*is_client=*/false,
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>())) {
std::tie(endpoint_binder_, tx_receiver_) = NewBinderPair(
[this](transaction_code_t tx_code, ReadableParcel* parcel, int uid) {
return this->wire_reader_->ProcessTransaction(tx_code, parcel, uid);
});
}
std::unique_ptr<Binder> WaitForClientBinder() {
return wire_reader_->RecvSetupTransport();
}
std::unique_ptr<Binder> GetEndpointBinderForClient() {
return std::move(endpoint_binder_);
}
private:
std::unique_ptr<WireReaderImpl> wire_reader_;
// The endpoint binder for client.
std::unique_ptr<Binder> endpoint_binder_;
std::unique_ptr<TransactionReceiver> tx_receiver_;
};
} // namespace
std::pair<grpc_core::Transport*, grpc_core::Transport*>
CreateClientServerBindersPairForTesting() {
ServerSetupTransportHelper helper;
std::unique_ptr<Binder> endpoint_binder = helper.GetEndpointBinderForClient();
grpc_core::Transport* client_transport = nullptr;
struct ThreadArgs {
std::unique_ptr<Binder> endpoint_binder;
grpc_core::Transport** client_transport;
} args;
args.endpoint_binder = std::move(endpoint_binder);
args.client_transport = &client_transport;
grpc_core::Thread client_thread(
"client-thread",
[](void* arg) {
ThreadArgs* args = static_cast<ThreadArgs*>(arg);
std::unique_ptr<Binder> endpoint_binder =
std::move(args->endpoint_binder);
*args->client_transport = grpc_create_binder_transport_client(
std::move(endpoint_binder),
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>());
},
&args);
client_thread.Start();
grpc_core::Transport* server_transport = grpc_create_binder_transport_server(
helper.WaitForClientBinder(),
std::make_shared<grpc::experimental::binder::UntrustedSecurityPolicy>());
client_thread.Join();
return std::make_pair(client_transport, server_transport);
}
std::shared_ptr<grpc::Channel> BinderChannelForTesting(
grpc::Server* server, const grpc::ChannelArguments& args) {
grpc_channel_args channel_args = args.c_channel_args();
return grpc::CreateChannelInternal(
"",
grpc_binder_channel_create_for_testing(server->c_server(), &channel_args,
nullptr),
std::vector<std::unique_ptr<
grpc::experimental::ClientInterceptorFactoryInterface>>());
}
} // namespace end2end_testing
} // namespace grpc_binder
grpc_channel* grpc_binder_channel_create_for_testing(
grpc_server* server, const grpc_channel_args* args, void* /*reserved*/) {
grpc_core::ExecCtx exec_ctx;
auto server_args = grpc_core::CoreConfiguration::Get()
.channel_args_preconditioning()
.PreconditionChannelArgs(args);
auto client_args =
server_args.Set(GRPC_ARG_DEFAULT_AUTHORITY, "test.authority");
grpc_core::Transport *client_transport, *server_transport;
std::tie(client_transport, server_transport) =
grpc_binder::end2end_testing::CreateClientServerBindersPairForTesting();
grpc_error_handle error = grpc_core::Server::FromC(server)->SetupTransport(
server_transport, nullptr, server_args, nullptr);
CHECK_OK(error);
auto channel = grpc_core::ChannelCreate(
"binder", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport);
CHECK_OK(channel);
return channel->release()->c_ptr();
}

@ -1,41 +0,0 @@
// 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_TEST_CORE_TRANSPORT_BINDER_END2END_TESTING_CHANNEL_CREATE_H
#define GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_TESTING_CHANNEL_CREATE_H
#include <grpcpp/grpcpp.h>
#include <utility>
#include "src/core/ext/transport/binder/transport/binder_transport.h"
#include "src/core/server/server.h"
#include "test/core/transport/binder/end2end/fake_binder.h"
namespace grpc_binder {
namespace end2end_testing {
std::pair<grpc_core::Transport*, grpc_core::Transport*>
CreateClientServerBindersPairForTesting();
std::shared_ptr<grpc::Channel> BinderChannelForTesting(
grpc::Server* server, const grpc::ChannelArguments& args);
} // namespace end2end_testing
} // namespace grpc_binder
grpc_channel* grpc_binder_channel_create_for_testing(
grpc_server* server, const grpc_channel_args* args, void* /*reserved*/);
#endif // GRPC_TEST_CORE_TRANSPORT_BINDER_END2END_TESTING_CHANNEL_CREATE_H

@ -1,74 +0,0 @@
// 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/client/endpoint_binder_pool.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <cassert>
#include <string>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/mock_objects.h"
namespace grpc_binder {
class CallbackChecker {
public:
MOCK_METHOD(void, Cb, (std::unique_ptr<grpc_binder::Binder>), ());
};
TEST(EndpointBinderPoolTest, AddBeforeGet) {
EndpointBinderPool pool;
auto b = std::make_unique<grpc_binder::MockBinder>();
CallbackChecker cc;
pool.AddEndpointBinder("test", std::move(b));
// TODO(mingcl): Use pointer matcher to verify it is `b` being passed back
// here. It is only available in newer gtest version
EXPECT_CALL(cc, Cb(testing::_));
pool.GetEndpointBinder(
"test", std::bind(&CallbackChecker::Cb, &cc, std::placeholders::_1));
}
TEST(EndpointBinderPoolTest, GetBeforeAdd) {
EndpointBinderPool pool;
auto b = std::make_unique<grpc_binder::MockBinder>();
CallbackChecker cc;
EXPECT_CALL(cc, Cb(testing::_)).Times(0);
pool.GetEndpointBinder(
"test", std::bind(&CallbackChecker::Cb, &cc, std::placeholders::_1));
EXPECT_CALL(cc, Cb(testing::_)).Times(1);
pool.AddEndpointBinder("test", std::move(b));
}
TEST(EndpointBinderPoolTest, ExpectNotCalled) {
EndpointBinderPool pool;
auto b = std::make_unique<grpc_binder::MockBinder>();
CallbackChecker cc;
EXPECT_CALL(cc, Cb(testing::_)).Times(0);
pool.GetEndpointBinder(
"test", std::bind(&CallbackChecker::Cb, &cc, std::placeholders::_1));
}
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1,55 +0,0 @@
// 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 "test/core/transport/binder/mock_objects.h"
#include <memory>
#include "absl/memory/memory.h"
namespace grpc_binder {
using ::testing::Return;
MockReadableParcel::MockReadableParcel() {
ON_CALL(*this, ReadBinder).WillByDefault([](std::unique_ptr<Binder>* binder) {
*binder = std::make_unique<MockBinder>();
return absl::OkStatus();
});
ON_CALL(*this, ReadInt32).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, ReadByteArray).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, ReadString).WillByDefault(Return(absl::OkStatus()));
}
MockWritableParcel::MockWritableParcel() {
ON_CALL(*this, WriteInt32).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, WriteBinder).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, WriteString).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, WriteByteArray).WillByDefault(Return(absl::OkStatus()));
}
MockBinder::MockBinder() {
ON_CALL(*this, PrepareTransaction).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, Transact).WillByDefault(Return(absl::OkStatus()));
ON_CALL(*this, GetWritableParcel).WillByDefault(Return(&mock_input_));
ON_CALL(*this, ConstructTxReceiver)
.WillByDefault(
[this](grpc_core::RefCountedPtr<WireReader> /*wire_reader_ref*/,
TransactionReceiver::OnTransactCb cb) {
return std::make_unique<MockTransactionReceiver>(
cb, BinderTransportTxCode::SETUP_TRANSPORT, &mock_output_);
});
}
} // namespace grpc_binder

@ -1,121 +0,0 @@
// 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_TEST_CORE_TRANSPORT_BINDER_MOCK_OBJECTS_H
#define GRPC_TEST_CORE_TRANSPORT_BINDER_MOCK_OBJECTS_H
#include <gmock/gmock.h>
#include "src/core/ext/transport/binder/utils/transport_stream_receiver.h"
#include "src/core/ext/transport/binder/wire_format/binder.h"
#include "src/core/ext/transport/binder/wire_format/binder_constants.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader.h"
#include "src/core/ext/transport/binder/wire_format/wire_writer.h"
namespace grpc_binder {
class MockWritableParcel : public WritableParcel {
public:
MOCK_METHOD(int32_t, GetDataSize, (), (const, override));
MOCK_METHOD(absl::Status, WriteInt32, (int32_t), (override));
MOCK_METHOD(absl::Status, WriteInt64, (int64_t), (override));
MOCK_METHOD(absl::Status, WriteBinder, (HasRawBinder*), (override));
MOCK_METHOD(absl::Status, WriteString, (absl::string_view), (override));
MOCK_METHOD(absl::Status, WriteByteArray, (const int8_t*, int32_t),
(override));
MockWritableParcel();
};
class MockReadableParcel : public ReadableParcel {
public:
MOCK_METHOD(int32_t, GetDataSize, (), (const, override));
MOCK_METHOD(absl::Status, ReadInt32, (int32_t*), (override));
MOCK_METHOD(absl::Status, ReadInt64, (int64_t*), (override));
MOCK_METHOD(absl::Status, ReadBinder, (std::unique_ptr<Binder>*), (override));
MOCK_METHOD(absl::Status, ReadByteArray, (std::string*), (override));
MOCK_METHOD(absl::Status, ReadString, (std::string*), (override));
MockReadableParcel();
};
class MockBinder : public Binder {
public:
MOCK_METHOD(void, Initialize, (), (override));
MOCK_METHOD(absl::Status, PrepareTransaction, (), (override));
MOCK_METHOD(absl::Status, Transact, (BinderTransportTxCode), (override));
MOCK_METHOD(WritableParcel*, GetWritableParcel, (), (const, override));
MOCK_METHOD(std::unique_ptr<TransactionReceiver>, ConstructTxReceiver,
(grpc_core::RefCountedPtr<WireReader>,
TransactionReceiver::OnTransactCb),
(const, override));
MOCK_METHOD(void*, GetRawBinder, (), (override));
MockBinder();
MockWritableParcel& GetWriter() { return mock_input_; }
MockReadableParcel& GetReader() { return mock_output_; }
private:
MockWritableParcel mock_input_;
MockReadableParcel mock_output_;
};
// TODO(waynetu): Implement transaction injection later for more thorough
// testing.
class MockTransactionReceiver : public TransactionReceiver {
public:
explicit MockTransactionReceiver(OnTransactCb transact_cb,
BinderTransportTxCode code,
MockReadableParcel* output) {
if (code == BinderTransportTxCode::SETUP_TRANSPORT) {
EXPECT_CALL(*output, ReadInt32).WillOnce([](int32_t* version) {
*version = 1;
return absl::OkStatus();
});
}
transact_cb(static_cast<transaction_code_t>(code), output, /*uid=*/0)
.IgnoreError();
}
MOCK_METHOD(void*, GetRawBinder, (), (override));
};
class MockWireWriter : public WireWriter {
public:
MOCK_METHOD(absl::Status, RpcCall, (std::unique_ptr<Transaction>),
(override));
MOCK_METHOD(absl::Status, SendAck, (int64_t), (override));
MOCK_METHOD(void, OnAckReceived, (int64_t), (override));
};
class MockTransportStreamReceiver : public TransportStreamReceiver {
public:
MOCK_METHOD(void, RegisterRecvInitialMetadata,
(StreamIdentifier, InitialMetadataCallbackType), (override));
MOCK_METHOD(void, RegisterRecvMessage,
(StreamIdentifier, MessageDataCallbackType), (override));
MOCK_METHOD(void, RegisterRecvTrailingMetadata,
(StreamIdentifier, TrailingMetadataCallbackType), (override));
MOCK_METHOD(void, NotifyRecvInitialMetadata,
(StreamIdentifier, absl::StatusOr<Metadata>), (override));
MOCK_METHOD(void, NotifyRecvMessage,
(StreamIdentifier, absl::StatusOr<std::string>), (override));
MOCK_METHOD(void, NotifyRecvTrailingMetadata,
(StreamIdentifier, absl::StatusOr<Metadata>, int), (override));
MOCK_METHOD(void, CancelStream, (StreamIdentifier), (override));
};
} // namespace grpc_binder
#endif // GRPC_TEST_CORE_TRANSPORT_BINDER_MOCK_OBJECTS_H

@ -1,287 +0,0 @@
// 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include <cassert>
#include <string>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "src/core/ext/transport/binder/utils/transport_stream_receiver_impl.h"
#include "test/core/test_util/test_config.h"
namespace grpc_binder {
namespace {
// TODO(waynetu): These are hacks to make callbacks aware of their stream IDs
// and sequence numbers. Remove/Refactor these hacks when possible.
template <typename T>
std::pair<StreamIdentifier, int> Decode(const T& /*data*/) {
assert(false && "This should not be called");
return {};
}
template <>
std::pair<StreamIdentifier, int> Decode<std::string>(const std::string& data) {
assert(data.size() == sizeof(StreamIdentifier) + sizeof(int));
StreamIdentifier id{};
int seq_num{};
std::memcpy(&id, data.data(), sizeof(StreamIdentifier));
std::memcpy(&seq_num, data.data() + sizeof(StreamIdentifier), sizeof(int));
return std::make_pair(id, seq_num);
}
template <>
std::pair<StreamIdentifier, int> Decode<Metadata>(const Metadata& data) {
assert(data.size() == 1);
const std::string& encoding = data[0].first;
return Decode(encoding);
}
template <typename T>
T Encode(StreamIdentifier /*id*/, int /*seq_num*/) {
assert(false && "This should not be called");
return {};
}
template <>
std::string Encode<std::string>(StreamIdentifier id, int seq_num) {
char result[sizeof(StreamIdentifier) + sizeof(int)];
std::memcpy(result, &id, sizeof(StreamIdentifier));
std::memcpy(result + sizeof(StreamIdentifier), &seq_num, sizeof(int));
return std::string(result, sizeof(StreamIdentifier) + sizeof(int));
}
template <>
Metadata Encode<Metadata>(StreamIdentifier id, int seq_num) {
return {{Encode<std::string>(id, seq_num), ""}};
}
MATCHER_P2(StreamIdAndSeqNumMatch, id, seq_num, "") {
auto p = Decode(arg.value());
return p.first == id && p.second == seq_num;
}
// MockCallback is used to verify the every callback passed to transaction
// receiver will eventually be invoked with the artifact of its corresponding
// binder transaction.
template <typename FirstArg, typename... TrailingArgs>
class MockCallback {
public:
explicit MockCallback(StreamIdentifier id, int seq_num)
: id_(id), seq_num_(seq_num) {}
MOCK_METHOD(void, ActualCallback, (FirstArg), ());
std::function<void(FirstArg, TrailingArgs...)> GetHandle() {
return [this](FirstArg first_arg, TrailingArgs...) {
this->ActualCallback(first_arg);
};
}
void ExpectCallbackInvocation() {
EXPECT_CALL(*this, ActualCallback(StreamIdAndSeqNumMatch(id_, seq_num_)));
}
private:
StreamIdentifier id_;
int seq_num_;
};
using MockInitialMetadataCallback = MockCallback<absl::StatusOr<Metadata>>;
using MockMessageCallback = MockCallback<absl::StatusOr<std::string>>;
using MockTrailingMetadataCallback =
MockCallback<absl::StatusOr<Metadata>, int>;
class MockOpBatch {
public:
MockOpBatch(StreamIdentifier id, int flag, int seq_num)
: id_(id), flag_(flag), seq_num_(seq_num) {
if (flag_ & kFlagPrefix) {
initial_metadata_callback_ =
std::make_unique<MockInitialMetadataCallback>(id_, seq_num_);
}
if (flag_ & kFlagMessageData) {
message_callback_ = std::make_unique<MockMessageCallback>(id_, seq_num_);
}
if (flag_ & kFlagSuffix) {
trailing_metadata_callback_ =
std::make_unique<MockTrailingMetadataCallback>(id_, seq_num_);
}
}
void Complete(TransportStreamReceiver& receiver) {
if (flag_ & kFlagPrefix) {
initial_metadata_callback_->ExpectCallbackInvocation();
receiver.NotifyRecvInitialMetadata(id_, Encode<Metadata>(id_, seq_num_));
}
if (flag_ & kFlagMessageData) {
message_callback_->ExpectCallbackInvocation();
receiver.NotifyRecvMessage(id_, Encode<std::string>(id_, seq_num_));
}
if (flag_ & kFlagSuffix) {
trailing_metadata_callback_->ExpectCallbackInvocation();
receiver.NotifyRecvTrailingMetadata(id_, Encode<Metadata>(id_, seq_num_),
0);
}
}
void RequestRecv(TransportStreamReceiver& receiver) {
if (flag_ & kFlagPrefix) {
receiver.RegisterRecvInitialMetadata(
id_, initial_metadata_callback_->GetHandle());
}
if (flag_ & kFlagMessageData) {
receiver.RegisterRecvMessage(id_, message_callback_->GetHandle());
}
if (flag_ & kFlagSuffix) {
receiver.RegisterRecvTrailingMetadata(
id_, trailing_metadata_callback_->GetHandle());
}
}
MockOpBatch NextBatch(int flag) const {
return MockOpBatch(id_, flag, seq_num_ + 1);
}
private:
std::unique_ptr<MockInitialMetadataCallback> initial_metadata_callback_;
std::unique_ptr<MockMessageCallback> message_callback_;
std::unique_ptr<MockTrailingMetadataCallback> trailing_metadata_callback_;
int id_, flag_, seq_num_;
};
class TransportStreamReceiverTest : public ::testing::Test {
protected:
MockOpBatch NewGrpcStream(int flag) {
return MockOpBatch(current_id_++, flag, 0);
}
StreamIdentifier current_id_ = 0;
};
const int kFlagAll = kFlagPrefix | kFlagMessageData | kFlagSuffix;
} // namespace
TEST_F(TransportStreamReceiverTest, MultipleStreamRequestThenComplete) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagAll);
t0.RequestRecv(receiver);
t0.Complete(receiver);
}
TEST_F(TransportStreamReceiverTest, MultipleStreamCompleteThenRequest) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagAll);
t0.Complete(receiver);
t0.RequestRecv(receiver);
}
TEST_F(TransportStreamReceiverTest, MultipleStreamInterleaved) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagAll);
MockOpBatch t1 = NewGrpcStream(kFlagAll);
t1.Complete(receiver);
t0.Complete(receiver);
t0.RequestRecv(receiver);
t1.RequestRecv(receiver);
}
TEST_F(TransportStreamReceiverTest, MultipleStreamInterleavedReversed) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagAll);
MockOpBatch t1 = NewGrpcStream(kFlagAll);
t0.RequestRecv(receiver);
t1.RequestRecv(receiver);
t1.Complete(receiver);
t0.Complete(receiver);
}
TEST_F(TransportStreamReceiverTest, MultipleStreamMoreInterleaved) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagAll);
MockOpBatch t1 = NewGrpcStream(kFlagAll);
t0.RequestRecv(receiver);
t1.Complete(receiver);
MockOpBatch t2 = NewGrpcStream(kFlagAll);
t2.RequestRecv(receiver);
t0.Complete(receiver);
t1.RequestRecv(receiver);
t2.Complete(receiver);
}
TEST_F(TransportStreamReceiverTest, SingleStreamUnaryCall) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagPrefix);
MockOpBatch t1 = t0.NextBatch(kFlagMessageData);
MockOpBatch t2 = t1.NextBatch(kFlagSuffix);
t0.RequestRecv(receiver);
t1.RequestRecv(receiver);
t2.RequestRecv(receiver);
t0.Complete(receiver);
t1.Complete(receiver);
t2.Complete(receiver);
}
TEST_F(TransportStreamReceiverTest, SingleStreamStreamingCall) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagPrefix);
t0.RequestRecv(receiver);
t0.Complete(receiver);
MockOpBatch t1 = t0.NextBatch(kFlagMessageData);
t1.Complete(receiver);
t1.RequestRecv(receiver);
MockOpBatch t2 = t1.NextBatch(kFlagMessageData);
t2.RequestRecv(receiver);
t2.Complete(receiver);
MockOpBatch t3 = t2.NextBatch(kFlagMessageData);
MockOpBatch t4 = t3.NextBatch(kFlagMessageData);
t3.Complete(receiver);
t4.Complete(receiver);
t3.RequestRecv(receiver);
t4.RequestRecv(receiver);
}
TEST_F(TransportStreamReceiverTest, DISABLED_SingleStreamBufferedCallbacks) {
TransportStreamReceiverImpl receiver(/*is_client=*/true);
MockOpBatch t0 = NewGrpcStream(kFlagPrefix);
MockOpBatch t1 = t0.NextBatch(kFlagMessageData);
MockOpBatch t2 = t1.NextBatch(kFlagMessageData);
MockOpBatch t3 = t2.NextBatch(kFlagSuffix);
t0.RequestRecv(receiver);
// TODO(waynetu): Can gRPC issues recv_message before it actually receives the
// previous one?
t1.RequestRecv(receiver);
t2.RequestRecv(receiver);
t3.RequestRecv(receiver);
t0.Complete(receiver);
t1.Complete(receiver);
t2.Complete(receiver);
t3.Complete(receiver);
}
// TODO(waynetu): Should we have some concurrent stress tests to make sure that
// thread safety is well taken care of?
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -1,376 +0,0 @@
// 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.
// Unit tests for WireReaderImpl.
//
// WireReaderImpl is responsible for turning incoming transactions into
// top-level metadata. The following tests verify that the interactions between
// WireReaderImpl and both the output (readable) parcel and the transport stream
// receiver are correct in all possible situations.
#include <grpc/grpc.h>
#include <grpcpp/security/binder_security_policy.h>
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include "absl/memory/memory.h"
#include "src/core/ext/transport/binder/wire_format/wire_reader_impl.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/mock_objects.h"
namespace grpc_binder {
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
namespace {
class WireReaderTest : public ::testing::Test {
protected:
void SetUp() override { SetUp(true); }
void SetUp(bool is_client) {
transport_stream_receiver_ =
std::make_shared<StrictMock<MockTransportStreamReceiver>>();
wire_reader_ = std::make_shared<WireReaderImpl>(
transport_stream_receiver_, is_client,
std::make_shared<
grpc::experimental::binder::UntrustedSecurityPolicy>());
}
void ExpectReadInt32(int result) {
EXPECT_CALL(mock_readable_parcel_, ReadInt32)
.WillOnce(DoAll(SetArgPointee<0>(result), Return(absl::OkStatus())));
}
void ExpectReadByteArray(const std::string& buffer) {
ExpectReadInt32(buffer.length());
if (!buffer.empty()) {
EXPECT_CALL(mock_readable_parcel_, ReadByteArray)
.WillOnce([buffer](std::string* data) {
*data = buffer;
return absl::OkStatus();
});
}
}
void ExpectReadString(const std::string& str) {
EXPECT_CALL(mock_readable_parcel_, ReadString)
.WillOnce([str](std::string* out) {
*out = str;
return absl::OkStatus();
});
}
void UnblockSetupTransport() {
// SETUP_TRANSPORT should finish before we can proceed with any other
// requests and streaming calls. The MockBinder will construct a
// MockTransactionReceiver, which will then sends SETUP_TRANSPORT request
// back to us.
wire_reader_->SetupTransport(std::make_unique<MockBinder>());
}
template <typename T>
absl::Status CallProcessTransaction(T tx_code) {
return wire_reader_->ProcessTransaction(
static_cast<transaction_code_t>(tx_code), &mock_readable_parcel_,
/*uid=*/0);
}
std::shared_ptr<StrictMock<MockTransportStreamReceiver>>
transport_stream_receiver_;
std::shared_ptr<WireReaderImpl> wire_reader_;
MockReadableParcel mock_readable_parcel_;
};
MATCHER_P(StatusOrStrEq, target, "") {
if (!arg.ok()) return false;
return arg.value() == target;
}
MATCHER_P(StatusOrContainerEq, target, "") {
if (!arg.ok()) return false;
return arg.value() == target;
}
} // namespace
TEST_F(WireReaderTest, SetupTransport) {
auto mock_binder = std::make_unique<MockBinder>();
MockBinder& mock_binder_ref = *mock_binder;
::testing::InSequence sequence;
EXPECT_CALL(mock_binder_ref, Initialize);
EXPECT_CALL(mock_binder_ref, PrepareTransaction);
const MockReadableParcel mock_readable_parcel;
EXPECT_CALL(mock_binder_ref, GetWritableParcel);
// Write version.
EXPECT_CALL(mock_binder_ref.GetWriter(), WriteInt32(1));
wire_reader_->SetupTransport(std::move(mock_binder));
}
TEST_F(WireReaderTest, ProcessTransactionControlMessageSetupTransport) {
::testing::InSequence sequence;
UnblockSetupTransport();
}
TEST_F(WireReaderTest, ProcessTransactionControlMessagePingResponse) {
::testing::InSequence sequence;
UnblockSetupTransport();
EXPECT_CALL(mock_readable_parcel_, ReadInt32);
EXPECT_TRUE(
CallProcessTransaction(BinderTransportTxCode::PING_RESPONSE).ok());
}
TEST_F(WireReaderTest, ProcessTransactionServerRpcDataEmptyFlagIgnored) {
::testing::InSequence sequence;
UnblockSetupTransport();
// first transaction: empty flag
ExpectReadInt32(0);
// Won't further read sequence number.
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest,
ProcessTransactionServerRpcDataFlagPrefixWithoutMetadata) {
::testing::InSequence sequence;
UnblockSetupTransport();
// flag
ExpectReadInt32(kFlagPrefix);
// sequence number
ExpectReadInt32(0);
// count
ExpectReadInt32(0);
EXPECT_CALL(
*transport_stream_receiver_,
NotifyRecvInitialMetadata(kFirstCallId, StatusOrContainerEq(Metadata{})));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, ProcessTransactionServerRpcDataFlagPrefixWithMetadata) {
::testing::InSequence sequence;
UnblockSetupTransport();
// flag
ExpectReadInt32(kFlagPrefix);
// sequence number
ExpectReadInt32(0);
const std::vector<std::pair<std::string, std::string>> kMetadata = {
{"", ""},
{"", "value"},
{"key", ""},
{"key", "value"},
{"another-key", "another-value"},
};
// count
ExpectReadInt32(kMetadata.size());
for (const auto& md : kMetadata) {
// metadata key
ExpectReadByteArray(md.first);
// metadata val
// TODO(waynetu): metadata value can also be "parcelable".
ExpectReadByteArray(md.second);
}
EXPECT_CALL(
*transport_stream_receiver_,
NotifyRecvInitialMetadata(kFirstCallId, StatusOrContainerEq(kMetadata)));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, ProcessTransactionServerRpcDataFlagMessageDataNonEmpty) {
::testing::InSequence sequence;
UnblockSetupTransport();
// flag
ExpectReadInt32(kFlagMessageData);
// sequence number
ExpectReadInt32(0);
// message data
// TODO(waynetu): message data can also be "parcelable".
const std::string kMessageData = "message data";
ExpectReadByteArray(kMessageData);
EXPECT_CALL(*transport_stream_receiver_,
NotifyRecvMessage(kFirstCallId, StatusOrStrEq(kMessageData)));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, ProcessTransactionServerRpcDataFlagMessageDataEmpty) {
::testing::InSequence sequence;
UnblockSetupTransport();
// flag
ExpectReadInt32(kFlagMessageData);
// sequence number
ExpectReadInt32(0);
// message data
// TODO(waynetu): message data can also be "parcelable".
const std::string kMessageData;
ExpectReadByteArray(kMessageData);
EXPECT_CALL(*transport_stream_receiver_,
NotifyRecvMessage(kFirstCallId, StatusOrStrEq(kMessageData)));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, ProcessTransactionServerRpcDataFlagSuffixWithStatus) {
::testing::InSequence sequence;
UnblockSetupTransport();
constexpr int kStatus = 0x1234;
// flag
ExpectReadInt32(kFlagSuffix | kFlagStatusDescription | (kStatus << 16));
// sequence number
ExpectReadInt32(0);
// status description
EXPECT_CALL(mock_readable_parcel_, ReadString);
// metadata count
ExpectReadInt32(0);
EXPECT_CALL(*transport_stream_receiver_,
NotifyRecvTrailingMetadata(
kFirstCallId, StatusOrContainerEq(Metadata{}), kStatus));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, ProcessTransactionServerRpcDataFlagSuffixWithoutStatus) {
::testing::InSequence sequence;
UnblockSetupTransport();
// flag
ExpectReadInt32(kFlagSuffix);
// sequence number
ExpectReadInt32(0);
// No status description
// metadata count
ExpectReadInt32(0);
EXPECT_CALL(*transport_stream_receiver_,
NotifyRecvTrailingMetadata(kFirstCallId,
StatusOrContainerEq(Metadata{}), 0));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, InBoundFlowControl) {
::testing::InSequence sequence;
UnblockSetupTransport();
// data size
EXPECT_CALL(mock_readable_parcel_, GetDataSize).WillOnce(Return(1000));
// flag
ExpectReadInt32(kFlagMessageData | kFlagMessageDataIsPartial);
// sequence number
ExpectReadInt32(0);
// message size
ExpectReadInt32(1000);
EXPECT_CALL(mock_readable_parcel_, ReadByteArray)
.WillOnce(DoAll(SetArgPointee<0>(std::string(1000, 'a')),
Return(absl::OkStatus())));
// Data is not completed. No callback will be triggered.
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
EXPECT_CALL(mock_readable_parcel_, GetDataSize).WillOnce(Return(1000));
// flag
ExpectReadInt32(kFlagMessageData);
// sequence number
ExpectReadInt32(1);
// message size
ExpectReadInt32(1000);
EXPECT_CALL(mock_readable_parcel_, ReadByteArray)
.WillOnce(DoAll(SetArgPointee<0>(std::string(1000, 'b')),
Return(absl::OkStatus())));
EXPECT_CALL(*transport_stream_receiver_,
NotifyRecvMessage(kFirstCallId,
StatusOrContainerEq(std::string(1000, 'a') +
std::string(1000, 'b'))));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
TEST_F(WireReaderTest, ServerInitialMetadata) {
SetUp(/*is_client=*/false);
::testing::InSequence sequence;
UnblockSetupTransport();
// flag
ExpectReadInt32(kFlagPrefix);
// sequence number
ExpectReadInt32(0);
const std::vector<std::pair<std::string, std::string>> kMetadata = {
{"", ""},
{"", "value"},
{"key", ""},
{"key", "value"},
{"another-key", "another-value"},
};
// method ref
ExpectReadString("test.service/rpc.method");
// metadata
{
// count
ExpectReadInt32(kMetadata.size());
for (const auto& md : kMetadata) {
// metadata key
ExpectReadByteArray(md.first);
// metadata val
// TODO(waynetu): metadata value can also be "parcelable".
ExpectReadByteArray(md.second);
}
}
// Since path and authority is not encoded as metadata in wire format,
// wire_reader implementation should insert them as metadata before passing
// to transport layer.
auto metadata_expectation = kMetadata;
metadata_expectation.push_back({":path", "/test.service/rpc.method"});
metadata_expectation.push_back({":authority", "binder.authority"});
EXPECT_CALL(*transport_stream_receiver_,
NotifyRecvInitialMetadata(
kFirstCallId, StatusOrContainerEq(metadata_expectation)));
EXPECT_TRUE(CallProcessTransaction(kFirstCallId).ok());
}
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
grpc_init();
auto results = RUN_ALL_TESTS();
grpc_shutdown();
return results;
}

@ -1,265 +0,0 @@
// 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/wire_format/wire_writer.h"
#include <grpcpp/impl/grpc_library.h>
#include <gtest/gtest.h>
#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include "test/core/test_util/test_config.h"
#include "test/core/transport/binder/mock_objects.h"
namespace grpc_binder {
using ::testing::Return;
MATCHER_P(StrEqInt8Ptr, target, "") {
return std::string(reinterpret_cast<const char*>(arg), target.size()) ==
target;
}
TEST(WireWriterTest, RpcCall) {
grpc::internal::GrpcLibrary init_lib;
// Required because wire writer uses combiner internally.
grpc_core::ExecCtx exec_ctx;
auto mock_binder = std::make_unique<MockBinder>();
MockBinder& mock_binder_ref = *mock_binder;
MockWritableParcel mock_writable_parcel;
ON_CALL(mock_binder_ref, GetWritableParcel)
.WillByDefault(Return(&mock_writable_parcel));
WireWriterImpl wire_writer(std::move(mock_binder));
auto ExpectWriteByteArray = [&](const std::string& target) {
// length
EXPECT_CALL(mock_writable_parcel, WriteInt32(target.size()));
if (!target.empty()) {
// content
EXPECT_CALL(mock_writable_parcel,
WriteByteArray(StrEqInt8Ptr(target), target.size()));
}
};
::testing::InSequence sequence;
int sequence_number = 0;
{
// flag
EXPECT_CALL(mock_writable_parcel, WriteInt32(0));
// sequence number
EXPECT_CALL(mock_writable_parcel, WriteInt32(sequence_number));
EXPECT_CALL(mock_binder_ref, Transact(BinderTransportTxCode(kFirstCallId)));
auto tx = std::make_unique<Transaction>(kFirstCallId, /*is_client=*/true);
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
sequence_number++;
grpc_core::ExecCtx::Get()->Flush();
}
{
// flag
EXPECT_CALL(mock_writable_parcel, WriteInt32(kFlagPrefix));
// sequence number. This is another stream so the sequence number starts
// with 0.
EXPECT_CALL(mock_writable_parcel, WriteInt32(0));
EXPECT_CALL(mock_writable_parcel,
WriteString(absl::string_view("/example/method/ref")));
const std::vector<std::pair<std::string, std::string>> kMetadata = {
{"", ""},
{"", "value"},
{"key", ""},
{"key", "value"},
{"another-key", "another-value"},
};
// Number of metadata
EXPECT_CALL(mock_writable_parcel, WriteInt32(kMetadata.size()));
for (const auto& md : kMetadata) {
ExpectWriteByteArray(md.first);
ExpectWriteByteArray(md.second);
}
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 1)));
auto tx =
std::make_unique<Transaction>(kFirstCallId + 1, /*is_client=*/true);
tx->SetPrefix(kMetadata);
tx->SetMethodRef("/example/method/ref");
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
grpc_core::ExecCtx::Get()->Flush();
}
{
// flag
EXPECT_CALL(mock_writable_parcel, WriteInt32(kFlagMessageData));
// sequence number
EXPECT_CALL(mock_writable_parcel, WriteInt32(sequence_number));
ExpectWriteByteArray("data");
EXPECT_CALL(mock_binder_ref, Transact(BinderTransportTxCode(kFirstCallId)));
auto tx = std::make_unique<Transaction>(kFirstCallId, /*is_client=*/true);
tx->SetData("data");
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
sequence_number++;
grpc_core::ExecCtx::Get()->Flush();
}
{
// flag
EXPECT_CALL(mock_writable_parcel, WriteInt32(kFlagSuffix));
// sequence number
EXPECT_CALL(mock_writable_parcel, WriteInt32(sequence_number));
EXPECT_CALL(mock_binder_ref, Transact(BinderTransportTxCode(kFirstCallId)));
auto tx = std::make_unique<Transaction>(kFirstCallId, /*is_client=*/true);
tx->SetSuffix({});
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
sequence_number++;
grpc_core::ExecCtx::Get()->Flush();
}
{
// flag
EXPECT_CALL(mock_writable_parcel,
WriteInt32(kFlagPrefix | kFlagMessageData | kFlagSuffix));
// sequence number
EXPECT_CALL(mock_writable_parcel, WriteInt32(sequence_number));
EXPECT_CALL(mock_writable_parcel,
WriteString(absl::string_view("/example/method/ref")));
const std::vector<std::pair<std::string, std::string>> kMetadata = {
{"", ""},
{"", "value"},
{"key", ""},
{"key", "value"},
{"another-key", "another-value"},
};
// Number of metadata
EXPECT_CALL(mock_writable_parcel, WriteInt32(kMetadata.size()));
for (const auto& md : kMetadata) {
ExpectWriteByteArray(md.first);
ExpectWriteByteArray(md.second);
}
// Empty message data
ExpectWriteByteArray("");
EXPECT_CALL(mock_binder_ref, Transact(BinderTransportTxCode(kFirstCallId)));
auto tx = std::make_unique<Transaction>(kFirstCallId, /*is_client=*/true);
// TODO(waynetu): Implement a helper function that automatically creates
// EXPECT_CALL based on the tx object.
tx->SetPrefix(kMetadata);
tx->SetMethodRef("/example/method/ref");
tx->SetData("");
tx->SetSuffix({});
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
sequence_number++;
grpc_core::ExecCtx::Get()->Flush();
}
// Really large message
{
EXPECT_CALL(mock_writable_parcel,
WriteInt32(kFlagMessageData | kFlagMessageDataIsPartial));
EXPECT_CALL(mock_writable_parcel, WriteInt32(0));
ExpectWriteByteArray(std::string(WireWriterImpl::kBlockSize, 'a'));
EXPECT_CALL(mock_writable_parcel, GetDataSize)
.WillOnce(Return(WireWriterImpl::kBlockSize));
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 2)));
EXPECT_CALL(mock_writable_parcel,
WriteInt32(kFlagMessageData | kFlagMessageDataIsPartial));
EXPECT_CALL(mock_writable_parcel, WriteInt32(1));
ExpectWriteByteArray(std::string(WireWriterImpl::kBlockSize, 'a'));
EXPECT_CALL(mock_writable_parcel, GetDataSize)
.WillOnce(Return(WireWriterImpl::kBlockSize));
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 2)));
EXPECT_CALL(mock_writable_parcel, WriteInt32(kFlagMessageData));
EXPECT_CALL(mock_writable_parcel, WriteInt32(2));
ExpectWriteByteArray("a");
EXPECT_CALL(mock_writable_parcel, GetDataSize).WillOnce(Return(1));
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 2)));
// Use a new stream.
auto tx =
std::make_unique<Transaction>(kFirstCallId + 2, /*is_client=*/true);
tx->SetData(std::string(2 * WireWriterImpl::kBlockSize + 1, 'a'));
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
grpc_core::ExecCtx::Get()->Flush();
}
// Really large message with metadata
{
EXPECT_CALL(
mock_writable_parcel,
WriteInt32(kFlagPrefix | kFlagMessageData | kFlagMessageDataIsPartial));
EXPECT_CALL(mock_writable_parcel, WriteInt32(0));
EXPECT_CALL(mock_writable_parcel, WriteString(absl::string_view("123")));
EXPECT_CALL(mock_writable_parcel, WriteInt32(0));
ExpectWriteByteArray(std::string(WireWriterImpl::kBlockSize, 'a'));
EXPECT_CALL(mock_writable_parcel, GetDataSize)
.WillOnce(Return(WireWriterImpl::kBlockSize));
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 3)));
EXPECT_CALL(mock_writable_parcel,
WriteInt32(kFlagMessageData | kFlagMessageDataIsPartial));
EXPECT_CALL(mock_writable_parcel, WriteInt32(1));
ExpectWriteByteArray(std::string(WireWriterImpl::kBlockSize, 'a'));
EXPECT_CALL(mock_writable_parcel, GetDataSize)
.WillOnce(Return(WireWriterImpl::kBlockSize));
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 3)));
EXPECT_CALL(mock_writable_parcel,
WriteInt32(kFlagMessageData | kFlagSuffix));
EXPECT_CALL(mock_writable_parcel, WriteInt32(2));
ExpectWriteByteArray("a");
EXPECT_CALL(mock_writable_parcel, GetDataSize).WillOnce(Return(1));
EXPECT_CALL(mock_binder_ref,
Transact(BinderTransportTxCode(kFirstCallId + 3)));
// Use a new stream.
auto tx =
std::make_unique<Transaction>(kFirstCallId + 3, /*is_client=*/true);
tx->SetPrefix({});
tx->SetMethodRef("123");
tx->SetData(std::string(2 * WireWriterImpl::kBlockSize + 1, 'a'));
tx->SetSuffix({});
EXPECT_TRUE(wire_writer.RpcCall(std::move(tx)).ok());
grpc_core::ExecCtx::Get()->Flush();
}
grpc_core::ExecCtx::Get()->Flush();
}
} // namespace grpc_binder
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(&argc, argv);
return RUN_ALL_TESTS();
}

@ -960,7 +960,6 @@ include/grpcpp/channel.h \
include/grpcpp/client_context.h \
include/grpcpp/completion_queue.h \
include/grpcpp/create_channel.h \
include/grpcpp/create_channel_binder.h \
include/grpcpp/create_channel_posix.h \
include/grpcpp/ext/call_metric_recorder.h \
include/grpcpp/ext/health_check_service_server_builder_option.h \
@ -1052,8 +1051,6 @@ include/grpcpp/security/audit_logging.h \
include/grpcpp/security/auth_context.h \
include/grpcpp/security/auth_metadata_processor.h \
include/grpcpp/security/authorization_policy_provider.h \
include/grpcpp/security/binder_credentials.h \
include/grpcpp/security/binder_security_policy.h \
include/grpcpp/security/credentials.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/tls_certificate_provider.h \

@ -960,7 +960,6 @@ include/grpcpp/channel.h \
include/grpcpp/client_context.h \
include/grpcpp/completion_queue.h \
include/grpcpp/create_channel.h \
include/grpcpp/create_channel_binder.h \
include/grpcpp/create_channel_posix.h \
include/grpcpp/ext/call_metric_recorder.h \
include/grpcpp/ext/health_check_service_server_builder_option.h \
@ -1052,8 +1051,6 @@ include/grpcpp/security/audit_logging.h \
include/grpcpp/security/auth_context.h \
include/grpcpp/security/auth_metadata_processor.h \
include/grpcpp/security/authorization_policy_provider.h \
include/grpcpp/security/binder_credentials.h \
include/grpcpp/security/binder_security_policy.h \
include/grpcpp/security/credentials.h \
include/grpcpp/security/server_credentials.h \
include/grpcpp/security/tls_certificate_provider.h \
@ -1173,44 +1170,6 @@ src/core/ext/filters/stateful_session/stateful_session_filter.cc \
src/core/ext/filters/stateful_session/stateful_session_filter.h \
src/core/ext/filters/stateful_session/stateful_session_service_config_parser.cc \
src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h \
src/core/ext/transport/binder/client/binder_connector.cc \
src/core/ext/transport/binder/client/binder_connector.h \
src/core/ext/transport/binder/client/channel_create.cc \
src/core/ext/transport/binder/client/channel_create_impl.cc \
src/core/ext/transport/binder/client/channel_create_impl.h \
src/core/ext/transport/binder/client/connection_id_generator.cc \
src/core/ext/transport/binder/client/connection_id_generator.h \
src/core/ext/transport/binder/client/endpoint_binder_pool.cc \
src/core/ext/transport/binder/client/endpoint_binder_pool.h \
src/core/ext/transport/binder/client/jni_utils.cc \
src/core/ext/transport/binder/client/jni_utils.h \
src/core/ext/transport/binder/client/security_policy_setting.cc \
src/core/ext/transport/binder/client/security_policy_setting.h \
src/core/ext/transport/binder/security_policy/binder_security_policy.cc \
src/core/ext/transport/binder/server/binder_server.cc \
src/core/ext/transport/binder/server/binder_server.h \
src/core/ext/transport/binder/server/binder_server_credentials.cc \
src/core/ext/transport/binder/transport/binder_stream.h \
src/core/ext/transport/binder/transport/binder_transport.cc \
src/core/ext/transport/binder/transport/binder_transport.h \
src/core/ext/transport/binder/utils/binder_auto_utils.h \
src/core/ext/transport/binder/utils/ndk_binder.cc \
src/core/ext/transport/binder/utils/ndk_binder.h \
src/core/ext/transport/binder/utils/transport_stream_receiver.h \
src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc \
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.cc \
src/core/ext/transport/binder/wire_format/binder_android.h \
src/core/ext/transport/binder/wire_format/binder_constants.cc \
src/core/ext/transport/binder/wire_format/binder_constants.h \
src/core/ext/transport/binder/wire_format/transaction.cc \
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.cc \
src/core/ext/transport/binder/wire_format/wire_reader_impl.h \
src/core/ext/transport/binder/wire_format/wire_writer.cc \
src/core/ext/transport/binder/wire_format/wire_writer.h \
src/core/ext/transport/chttp2/alpn/alpn.cc \
src/core/ext/transport/chttp2/alpn/alpn.h \
src/core/ext/transport/chttp2/client/chttp2_connector.cc \
@ -2716,7 +2675,6 @@ src/core/load_balancing/xds/xds_override_host.h \
src/core/load_balancing/xds/xds_wrr_locality.cc \
src/core/plugin_registry/grpc_plugin_registry.cc \
src/core/plugin_registry/grpc_plugin_registry_extra.cc \
src/core/resolver/binder/binder_resolver.cc \
src/core/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/resolver/dns/c_ares/dns_resolver_ares.h \
src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h \

@ -975,7 +975,6 @@ src/core/ext/filters/stateful_session/stateful_session_filter.h \
src/core/ext/filters/stateful_session/stateful_session_service_config_parser.cc \
src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h \
src/core/ext/transport/README.md \
src/core/ext/transport/binder/README.md \
src/core/ext/transport/chttp2/README.md \
src/core/ext/transport/chttp2/alpn/alpn.cc \
src/core/ext/transport/chttp2/alpn/alpn.h \
@ -2489,8 +2488,6 @@ src/core/load_balancing/xds/xds_wrr_locality.cc \
src/core/plugin_registry/grpc_plugin_registry.cc \
src/core/plugin_registry/grpc_plugin_registry_extra.cc \
src/core/resolver/README.md \
src/core/resolver/binder/README.md \
src/core/resolver/binder/binder_resolver.cc \
src/core/resolver/dns/c_ares/dns_resolver_ares.cc \
src/core/resolver/dns/c_ares/dns_resolver_ares.h \
src/core/resolver/dns/c_ares/grpc_ares_ev_driver.h \

@ -1065,78 +1065,6 @@
],
"uses_polling": true
},
{
"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,
"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,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "binder_transport_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -3147,30 +3075,6 @@
],
"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": "endpoint_binder_pool_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -3527,30 +3431,6 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "fake_binder_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -11395,30 +11275,6 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "transport_stream_receiver_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,
@ -11845,54 +11701,6 @@
],
"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": "wire_reader_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"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": "wire_writer_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": false
},
{
"args": [],
"benchmark": false,

Loading…
Cancel
Save