Merge branch 'master' into fix-win-core-e2e

pull/37918/head
AJ Heller 4 months ago
commit 9c7e8df653
  1. 4
      .github/workflows/pr-auto-fix.yaml
  2. 148
      BUILD
  3. 4734
      CMakeLists.txt
  4. 3
      Makefile
  5. 1
      Package.swift
  6. 12
      WORKSPACE
  7. 7
      bazel/experiments.bzl
  8. 6
      bazel/grpc_build_system.bzl
  9. 47
      bazel/grpc_deps.bzl
  10. 7
      bazel/grpc_extra_deps.bzl
  11. 6
      bazel/grpc_python_deps.bzl
  12. 3
      bazel/internal_python_rules.bzl
  13. 19
      bazel/rules_go.patch
  14. 1805
      build_autogenerated.yaml
  15. 2
      build_handwritten.yaml
  16. 2
      config.m4
  17. 2
      config.w32
  18. 8
      doc/naming.md
  19. 4
      examples/cpp/helloworld/cocoapods/HelloWorldCpp.xcodeproj/project.pbxproj
  20. 2
      examples/cpp/helloworld/cocoapods/Podfile
  21. 4
      examples/cpp/interceptors/README.md
  22. 6
      examples/objective-c/BUILD
  23. 4
      examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj
  24. 4
      examples/objective-c/auth_sample/AuthTestService.podspec
  25. 2
      examples/objective-c/auth_sample/Podfile
  26. 4
      examples/objective-c/helloworld/HelloWorld.podspec
  27. 4
      examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj
  28. 2
      examples/objective-c/helloworld/Podfile
  29. 4
      examples/objective-c/helloworld_macos/HelloWorld.podspec
  30. 4
      examples/objective-c/helloworld_macos/HelloWorld.xcodeproj/project.pbxproj
  31. 2
      examples/objective-c/helloworld_macos/Podfile
  32. 2
      examples/objective-c/route_guide/Podfile
  33. 4
      examples/objective-c/route_guide/RouteGuide.podspec
  34. 4
      examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj
  35. 67
      gRPC-C++.podspec
  36. 7
      gRPC-Core.podspec
  37. 6
      gRPC-ProtoRPC.podspec
  38. 6
      gRPC-RxLibrary.podspec
  39. 38
      gRPC.podspec
  40. 1
      grpc.gemspec
  41. 7
      include/grpc/support/port_platform.h
  42. 125
      include/grpcpp/create_channel_binder.h
  43. 43
      include/grpcpp/security/binder_credentials.h
  44. 82
      include/grpcpp/security/binder_security_policy.h
  45. 1
      package.xml
  46. 40
      src/core/BUILD
  47. 17
      src/core/client_channel/backup_poller.cc
  48. 10
      src/core/ext/transport/binder/README.md
  49. 134
      src/core/ext/transport/binder/client/binder_connector.cc
  50. 41
      src/core/ext/transport/binder/client/binder_connector.h
  51. 231
      src/core/ext/transport/binder/client/channel_create.cc
  52. 93
      src/core/ext/transport/binder/client/channel_create_impl.cc
  53. 42
      src/core/ext/transport/binder/client/channel_create_impl.h
  54. 69
      src/core/ext/transport/binder/client/connection_id_generator.cc
  55. 50
      src/core/ext/transport/binder/client/connection_id_generator.h
  56. 114
      src/core/ext/transport/binder/client/endpoint_binder_pool.cc
  57. 64
      src/core/ext/transport/binder/client/endpoint_binder_pool.h
  58. 138
      src/core/ext/transport/binder/client/jni_utils.cc
  59. 57
      src/core/ext/transport/binder/client/jni_utils.h
  60. 47
      src/core/ext/transport/binder/client/security_policy_setting.cc
  61. 49
      src/core/ext/transport/binder/client/security_policy_setting.h
  62. 0
      src/core/ext/transport/binder/java/WORKSPACE
  63. 30
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/BUILD
  64. 104
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/GrpcBinderConnection.java
  65. 40
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/GrpcCppServerBuilder.java
  66. 71
      src/core/ext/transport/binder/java/io/grpc/binder/cpp/NativeConnectionHelper.java
  67. 106
      src/core/ext/transport/binder/security_policy/binder_security_policy.cc
  68. 40
      src/core/ext/transport/binder/security_policy/security_policy.h
  69. 249
      src/core/ext/transport/binder/server/binder_server.cc
  70. 65
      src/core/ext/transport/binder/server/binder_server.h
  71. 71
      src/core/ext/transport/binder/server/binder_server_credentials.cc
  72. 117
      src/core/ext/transport/binder/transport/binder_stream.h
  73. 758
      src/core/ext/transport/binder/transport/binder_transport.cc
  74. 119
      src/core/ext/transport/binder/transport/binder_transport.h
  75. 76
      src/core/ext/transport/binder/utils/binder_auto_utils.h
  76. 218
      src/core/ext/transport/binder/utils/ndk_binder.cc
  77. 107
      src/core/ext/transport/binder/utils/ndk_binder.h
  78. 70
      src/core/ext/transport/binder/utils/transport_stream_receiver.h
  79. 257
      src/core/ext/transport/binder/utils/transport_stream_receiver_impl.cc
  80. 112
      src/core/ext/transport/binder/utils/transport_stream_receiver_impl.h
  81. 104
      src/core/ext/transport/binder/wire_format/binder.h
  82. 308
      src/core/ext/transport/binder/wire_format/binder_android.cc
  83. 121
      src/core/ext/transport/binder/wire_format/binder_android.h
  84. 29
      src/core/ext/transport/binder/wire_format/binder_constants.cc
  85. 43
      src/core/ext/transport/binder/wire_format/binder_constants.h
  86. 33
      src/core/ext/transport/binder/wire_format/transaction.cc
  87. 106
      src/core/ext/transport/binder/wire_format/transaction.h
  88. 38
      src/core/ext/transport/binder/wire_format/wire_reader.h
  89. 450
      src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
  90. 158
      src/core/ext/transport/binder/wire_format/wire_reader_impl.h
  91. 393
      src/core/ext/transport/binder/wire_format/wire_writer.cc
  92. 126
      src/core/ext/transport/binder/wire_format/wire_writer.h
  93. 37
      src/core/ext/transport/chaotic_good/client_transport.cc
  94. 33
      src/core/ext/transport/chaotic_good/server_transport.cc
  95. 3
      src/core/ext/transport/chaotic_good/server_transport.h
  96. 96
      src/core/ext/transport/chttp2/server/chttp2_server.cc
  97. 14
      src/core/ext/transport/chttp2/transport/parsing.cc
  98. 7
      src/core/lib/event_engine/posix_engine/posix_engine_listener.h
  99. 3
      src/core/lib/event_engine/resolved_address.cc
  100. 16
      src/core/lib/event_engine/utils.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -66,7 +66,7 @@ jobs:
run: test "${{ steps.check.outputs.result }}" = "stay"
# Setup to run sanity suite
- name: Install Python Interpreter
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: 3.8
- name: Install Python Packages
@ -90,7 +90,7 @@ jobs:
run: ANDROID_NDK_HOME= ${{ github.workspace }}/tools/distrib/sanitize.sh
# Report back with a PR if things are broken
- name: Create Pull Request
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5
with:
delete-branch: true
branch-suffix: short-commit-hash

148
BUILD

@ -19,7 +19,6 @@ load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
load(
"//bazel:grpc_build_system.bzl",
"grpc_cc_library",
"grpc_cc_proto_library",
"grpc_clang_cl_settings",
"grpc_filegroup",
"grpc_generate_one_off_targets",
@ -75,17 +74,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 +124,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 = [
@ -230,7 +209,7 @@ python_config_settings()
# This should be updated along with build_handwritten.yaml
g_stands_for = "groovy" # @unused
core_version = "44.0.0" # @unused
core_version = "44.1.0" # @unused
version = "1.68.0-dev" # @unused
@ -857,7 +836,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 +921,6 @@ grpc_cc_library(
"grpc++_xds_server",
],
},
{
"grpc_no_binder": [],
"//conditions:default": [
"grpc++_binder",
],
},
],
tags = ["nofixdeps"],
visibility = ["@grpc:public"],
@ -1079,112 +1051,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 = [
@ -2490,6 +2356,7 @@ grpc_cc_library(
"//src/core:default_event_engine",
"//src/core:env",
"//src/core:error",
"//src/core:experiments",
"//src/core:gpr_atm",
"//src/core:gpr_manual_constructor",
"//src/core:grpc_audit_logging",
@ -2577,6 +2444,7 @@ grpc_cc_library(
"//src/core:closure",
"//src/core:default_event_engine",
"//src/core:error",
"//src/core:experiments",
"//src/core:gpr_atm",
"//src/core:gpr_manual_constructor",
"//src/core:grpc_backend_metric_provider",
@ -4990,11 +4858,6 @@ grpc_upb_proto_reflection_library(
deps = ["@envoy_api//envoy/config/cluster/v3:pkg"],
)
grpc_cc_proto_library(
name = "envoy_config_core_cc_proto",
deps = ["@envoy_api//envoy/config/core/v3:pkg"],
)
grpc_upb_proto_library(
name = "envoy_config_core_upb",
deps = ["@envoy_api//envoy/config/core/v3:pkg"],
@ -5180,11 +5043,6 @@ grpc_upb_proto_reflection_library(
deps = ["@envoy_api//envoy/extensions/upstreams/http/v3:pkg"],
)
grpc_cc_proto_library(
name = "envoy_service_discovery_cc_proto",
deps = ["@envoy_api//envoy/service/discovery/v3:pkg"],
)
grpc_upb_proto_library(
name = "envoy_service_discovery_upb",
deps = ["@envoy_api//envoy/service/discovery/v3:pkg"],

4734
CMakeLists.txt generated

File diff suppressed because it is too large Load Diff

3
Makefile generated

@ -367,7 +367,7 @@ E = @echo
Q = @
endif
CORE_VERSION = 44.0.0
CORE_VERSION = 44.1.0
CPP_VERSION = 1.68.0-dev
CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
@ -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.
@ -85,7 +75,7 @@ load("@grpc_python_dependencies//:requirements.bzl", "install_deps")
install_deps()
load("@com_google_protobuf//bazel:system_python.bzl", "system_python")
load("@com_google_protobuf//python/dist:system_python.bzl", "system_python")
system_python(
name = "system_python",

@ -21,8 +21,10 @@ EXPERIMENT_ENABLES = {
"canary_client_privacy": "canary_client_privacy",
"client_privacy": "client_privacy",
"event_engine_application_callbacks": "event_engine_application_callbacks",
"event_engine_callback_cq": "event_engine_application_callbacks,event_engine_callback_cq",
"event_engine_client": "event_engine_client",
"event_engine_dns": "event_engine_dns",
"event_engine_dns_non_client_channel": "event_engine_dns_non_client_channel",
"event_engine_listener": "event_engine_listener",
"free_large_allocator": "free_large_allocator",
"local_connector_secure": "local_connector_secure",
@ -31,6 +33,7 @@ EXPERIMENT_ENABLES = {
"multiping": "multiping",
"pick_first_new": "pick_first_new",
"promise_based_inproc_transport": "promise_based_inproc_transport",
"rq_fast_reject": "rq_fast_reject",
"schedule_cancellation_over_write": "schedule_cancellation_over_write",
"server_privacy": "server_privacy",
"tcp_frame_size_tuning": "tcp_frame_size_tuning",
@ -44,6 +47,7 @@ EXPERIMENT_ENABLES = {
EXPERIMENT_POLLERS = [
"event_engine_client",
"event_engine_dns",
"event_engine_dns_non_client_channel",
"event_engine_listener",
]
@ -53,6 +57,7 @@ EXPERIMENTS = {
},
"off": {
"core_end2end_test": [
"event_engine_dns_non_client_channel",
"local_connector_secure",
],
"endpoint_test": [
@ -102,6 +107,7 @@ EXPERIMENTS = {
},
"off": {
"core_end2end_test": [
"event_engine_dns_non_client_channel",
"local_connector_secure",
],
"endpoint_test": [
@ -135,6 +141,7 @@ EXPERIMENTS = {
},
"off": {
"core_end2end_test": [
"event_engine_dns_non_client_channel",
"local_connector_secure",
],
"endpoint_test": [

@ -29,7 +29,6 @@ Contains macros used throughout the repo.
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_unit_test")
load("@build_bazel_rules_apple//apple/testing/default_runner:ios_test_runner.bzl", "ios_test_runner")
load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library")
load("@com_google_protobuf//bazel:upb_proto_library.bzl", "upb_proto_library", "upb_proto_reflection_library")
load("//bazel:cc_grpc_library.bzl", "cc_grpc_library")
load("//bazel:copts.bzl", "GRPC_DEFAULT_COPTS")
@ -290,7 +289,7 @@ def ios_cc_test(
size = kwargs.get("size"),
data = kwargs.get("data"),
tags = ios_tags,
minimum_os_version = "9.0",
minimum_os_version = "11.0",
runner = test_runner,
deps = ios_test_deps,
)
@ -795,9 +794,6 @@ def grpc_objc_library(
visibility = visibility,
)
def grpc_cc_proto_library(name, deps):
cc_proto_library(name = name, deps = deps)
def grpc_upb_proto_library(name, deps):
upb_proto_library(name = name, deps = deps)

@ -206,14 +206,45 @@ def grpc_deps():
],
)
# TODO(roth): Need to override version of rules_proto, because
# we're using a newer version of rules_go than the xDS protos are,
# and that requires a newer version of rules_proto. In turn, the
# newer version of rules_proto requires a newer version of
# bazel_features. So these two entries can go away once the xDS
# protos upgrade to the newer version of rules_go.
if "bazel_features" not in native.existing_rules():
http_archive(
name = "bazel_features",
sha256 = "5ac743bf5f05d88e84962e978811f2524df09602b789c92cf7ae2111ecdeda94",
strip_prefix = "bazel_features-1.14.0",
urls = [
"https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazel-contrib/bazel_features/releases/download/v1.14.0/bazel_features-v1.14.0.tar.gz",
"https://github.com/bazel-contrib/bazel_features/releases/download/v1.14.0/bazel_features-v1.14.0.tar.gz",
],
)
if "rules_proto" not in native.existing_rules():
http_archive(
name = "rules_proto",
sha256 = "6fb6767d1bef535310547e03247f7518b03487740c11b6c6adb7952033fe1295",
strip_prefix = "rules_proto-6.0.2",
urls = [
"https://storage.googleapis.com/grpc-bazel-mirror/github.com/bazelbuild/rules_proto/archive/refs/tags/6.0.2.tar.gz",
"https://github.com/bazelbuild/rules_proto/archive/refs/tags/6.0.2.tar.gz",
],
)
if "io_bazel_rules_go" not in native.existing_rules():
http_archive(
name = "io_bazel_rules_go",
sha256 = "69de5c704a05ff37862f7e0f5534d4f479418afc21806c887db544a316f3cb6b",
sha256 = "d93ef02f1e72c82d8bb3d5169519b36167b33cf68c252525e3b9d3d5dd143de7",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
"https://github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.49.0/rules_go-v0.49.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.49.0/rules_go-v0.49.0.zip",
],
patches = [
"@com_github_grpc_grpc//bazel:rules_go.patch",
],
patch_args = ["-p1"],
)
if "build_bazel_rules_apple" not in native.existing_rules():
@ -272,13 +303,9 @@ def grpc_deps():
if "com_envoyproxy_protoc_gen_validate" not in native.existing_rules():
http_archive(
name = "com_envoyproxy_protoc_gen_validate",
strip_prefix = "protoc-gen-validate-4694024279bdac52b77e22dc87808bd0fd732b69",
sha256 = "1e490b98005664d149b379a9529a6aa05932b8a11b76b4cd86f3d22d76346f47",
urls = [
"https://github.com/envoyproxy/protoc-gen-validate/archive/4694024279bdac52b77e22dc87808bd0fd732b69.tar.gz",
],
patches = ["@com_github_grpc_grpc//third_party:protoc-gen-validate.patch"],
patch_args = ["-p1"],
sha256 = "9372f9ecde8fbadf83c8c7de3dbb49b11067aa26fb608c501106d0b4bf06c28f",
strip_prefix = "protoc-gen-validate-1.0.4",
urls = ["https://github.com/bufbuild/protoc-gen-validate/archive/refs/tags/v1.0.4.zip"],
)
if "com_github_cncf_xds" not in native.existing_rules():

@ -13,6 +13,7 @@
# limitations under the License.
"""Loads the dependencies necessary for the external repositories defined in grpc_deps.bzl."""
load("@bazel_features//:deps.bzl", "bazel_features_deps")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
load("@build_bazel_apple_support//lib:repositories.bzl", "apple_support_dependencies")
load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies")
@ -22,6 +23,7 @@ load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
load("@envoy_api//bazel:repositories.bzl", "api_dependencies")
load("@google_cloud_cpp//bazel:google_cloud_cpp_deps.bzl", "google_cloud_cpp_deps")
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies")
load("@rules_python//python:repositories.bzl", "py_repositories")
def grpc_extra_deps(ignore_version_differences = False):
@ -49,10 +51,13 @@ def grpc_extra_deps(ignore_version_differences = False):
"""
protobuf_deps()
rules_proto_dependencies()
bazel_features_deps()
api_dependencies()
go_rules_dependencies()
go_register_toolchains(version = "1.20")
go_register_toolchains(version = "1.22.5")
gazelle_dependencies()
# Pull-in the go 3rd party dependencies for protoc_gen_validate, which is

@ -38,9 +38,9 @@ def grpc_python_deps():
http_archive(
name = "cython",
build_file = "@com_github_grpc_grpc//third_party:cython.BUILD",
sha256 = "a2da56cc22be823acf49741b9aa3aa116d4f07fa8e8b35a3cb08b8447b37c607",
strip_prefix = "cython-0.29.35",
sha256 = "2ec7d66d23d6da2328fb24f5c1bec6c63a59ec2e91027766ab904f417e1078aa",
strip_prefix = "cython-3.0.11",
urls = [
"https://github.com/cython/cython/archive/0.29.35.tar.gz",
"https://github.com/cython/cython/archive/3.0.11.tar.gz",
],
)

@ -14,6 +14,7 @@
"""Python-related rules intended only for use internal to the repo."""
load("//bazel:gevent_test.bzl", "py_grpc_gevent_test")
load("//bazel:logging_threshold_test.bzl", "py_grpc_logging_threshold_test")
def internal_py_grpc_test(name, **kwargs):
"""Runs a test under all supported environments.
@ -28,6 +29,7 @@ def internal_py_grpc_test(name, **kwargs):
**kwargs
)
py_grpc_gevent_test(name, **kwargs)
py_grpc_logging_threshold_test(name, **kwargs)
suite_kwargs = {}
if "visibility" in kwargs:
@ -38,6 +40,7 @@ def internal_py_grpc_test(name, **kwargs):
tests = [
name + ".native",
name + ".gevent",
name + ".logging_threshold",
],
**suite_kwargs
)

@ -0,0 +1,19 @@
# This patch works around a problem with Windows RBE described in
# https://github.com/bazelbuild/bazel/issues/11636. It can be removed
# once that issue is resolved.
diff --git a/go/private/rules/binary.bzl b/go/private/rules/binary.bzl
index 40a17f4d..2741ad71 100644
--- a/go/private/rules/binary.bzl
+++ b/go/private/rules/binary.bzl
@@ -462,8 +462,9 @@ exit /b %GO_EXIT_CODE%
content = cmd,
)
ctx.actions.run(
- executable = bat,
- inputs = sdk.headers + sdk.tools + sdk.srcs + ctx.files.srcs + [sdk.go],
+ executable = "cmd.exe",
+ arguments = ["/S", "/C", bat.path.replace("/", "\\")],
+ inputs = sdk.headers + sdk.tools + sdk.srcs + ctx.files.srcs + [sdk.go, bat],
outputs = [out, gotmp],
mnemonic = "GoToolchainBinaryBuild",
)

File diff suppressed because it is too large Load Diff

@ -12,7 +12,7 @@ settings:
'#08': Use "-preN" suffixes to identify pre-release versions
'#09': Per-language overrides are possible with (eg) ruby_version tag here
'#10': See the expand_version.py for all the quirks here
core_version: 44.0.0
core_version: 44.1.0
csharp_major_version: 2
g_stands_for: groovy
protobuf_version: 3.28.1

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");

@ -34,12 +34,12 @@ Most gRPC implementations support the following URI schemes:
resolver does not support this, but the c-ares based resolver
supports specifying this in the form "IP:port".)
- `unix:path`, `unix://absolute_path` -- Unix domain sockets (Unix systems only)
- `unix:path`, `unix:///absolute_path` -- Unix domain sockets (Unix systems only)
- `path` indicates the location of the desired socket.
- In the first form, the path may be relative or absolute; in the
second form, the path must be absolute (i.e., there will actually be
three slashes, two prior to the path and another to begin the
absolute path).
second form, the path must be absolute (i.e., the last of the three
slashes is actually part of the path, so the path part of the URI is
`/absolute_path`).
- `unix-abstract:abstract_path` -- Unix domain socket in abstract namespace (Unix systems only)
- `abstract_path` indicates a name in the abstract namespace.

@ -296,7 +296,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -345,7 +345,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;

@ -1,5 +1,5 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
platform :ios, '11.0'
install! 'cocoapods', :deterministic_uuids => false

@ -15,11 +15,11 @@ On the server-side, a very simple logging interceptor is added that simply logs
To run the server -
```
$ tools/bazel run examples/cpp/interceptors:server
$ tools/bazel run examples/cpp/interceptors:keyvaluestore_server
```
To run the client (on a different terminal) -
```
$ tools/bazel run examples/cpp/interceptors:client
$ tools/bazel run examples/cpp/interceptors:keyvaluestore_client
```

@ -56,7 +56,7 @@ ios_application(
"ipad",
],
infoplists = ["helloworld/HelloWorld/Info.plist"],
minimum_os_version = "9.0",
minimum_os_version = "11.0",
tags = ["manual"],
deps = [":HelloWorld-lib"],
)
@ -79,7 +79,7 @@ macos_application(
bundle_id = "io.grpc.HelloWorld",
entitlements = "helloworld_macos/HelloWorld/Helloworld.entitlements",
infoplists = ["helloworld_macos/HelloWorld/Info.plist"],
minimum_os_version = "10.13",
minimum_os_version = "10.14",
tags = ["manual"],
deps = [":HelloWorldMacos-lib"],
)
@ -112,7 +112,7 @@ ios_application(
"ipad",
],
infoplists = ["route_guide/Misc/Info.plist"],
minimum_os_version = "9.0",
minimum_os_version = "11.0",
tags = ["manual"],
deps = [":RouteGuideClient-lib"],
)

@ -287,7 +287,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -325,7 +325,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";

@ -7,8 +7,8 @@ Pod::Spec.new do |s|
s.summary = "AuthTestService example"
s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.14"
# Base directory where the .proto files are.
src = "../../protos"

@ -1,5 +1,5 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
platform :ios, '11.0'
install! 'cocoapods', :deterministic_uuids => false

@ -7,8 +7,8 @@ Pod::Spec.new do |s|
s.summary = "HelloWorld example"
s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.14"
# Base directory where the .proto files are.
src = "../../protos"

@ -274,7 +274,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -310,7 +310,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";

@ -1,5 +1,5 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
platform :ios, '11.0'
install! 'cocoapods', :deterministic_uuids => false

@ -7,8 +7,8 @@ Pod::Spec.new do |s|
s.summary = "HelloWorld example"
s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.14"
# Base directory where the .proto files are.
src = "../../protos"

@ -280,7 +280,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@ -332,7 +332,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};

@ -1,5 +1,5 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :macos, '10.12'
platform :macos, '10.14'
install! 'cocoapods', :deterministic_uuids => false

@ -1,5 +1,5 @@
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
platform :ios, '11.0'
install! 'cocoapods', :deterministic_uuids => false

@ -7,8 +7,8 @@ Pod::Spec.new do |s|
s.summary = "RouteGuide example"
s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.14"
# Base directory where the .proto files are.
src = "../../protos"

@ -287,7 +287,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -325,7 +325,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";

67
gRPC-C++.podspec generated

@ -34,9 +34,9 @@ Pod::Spec.new do |s|
:tag => "v#{version}",
}
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -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',

7
gRPC-Core.podspec generated

@ -38,9 +38,9 @@ Pod::Spec.new do |s|
# which was released in Cocoapods v1.2.0.
s.cocoapods_version = '>= 1.2.0'
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -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',

@ -33,9 +33,9 @@ Pod::Spec.new do |s|
:tag => "v#{version}",
}
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'

@ -33,9 +33,9 @@ Pod::Spec.new do |s|
:tag => "v#{version}",
}
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'

38
gRPC.podspec generated

@ -45,9 +45,9 @@ Pod::Spec.new do |s|
'CLANG_CXX_LANGUAGE_STANDARD' => 'c++14',
}
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
@ -80,9 +80,9 @@ Pod::Spec.new do |s|
"src/objective-c/GRPCClient/GRPCTypes.mm"
ss.dependency "gRPC-RxLibrary/Interface", version
ss.dependency "#{s.name}/Privacy", version
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
end
@ -116,9 +116,9 @@ Pod::Spec.new do |s|
ss.dependency "#{s.name}/Interface-Legacy", version
ss.dependency "#{s.name}/Privacy", version
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
end
@ -154,9 +154,9 @@ Pod::Spec.new do |s|
ss.dependency 'gRPC-Core', version
ss.dependency 'gRPC-RxLibrary', version
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
end
@ -172,16 +172,16 @@ Pod::Spec.new do |s|
ss.dependency 'gRPC-Core/Cronet-Implementation', version
ss.dependency 'CronetFramework'
ss.ios.deployment_target = '10.0'
ss.ios.deployment_target = '11.0'
end
# CFStream is now default. Leaving this subspec only for compatibility purpose.
s.subspec 'CFStream' do |ss|
ss.dependency "#{s.name}/GRPCCore", version
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
end
@ -192,9 +192,9 @@ Pod::Spec.new do |s|
ss.source_files = 'src/objective-c/GRPCClient/internal_testing/*.{h,mm}'
ss.header_mappings_dir = 'src/objective-c/GRPCClient'
s.ios.deployment_target = '10.0'
s.osx.deployment_target = '10.12'
s.tvos.deployment_target = '12.0'
s.ios.deployment_target = '11.0'
s.osx.deployment_target = '10.14'
s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '6.0'
s.visionos.deployment_target = '1.0'
end

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.
@ -195,6 +194,12 @@
#define GPR_HAS_PTHREAD_H 1
#define GPR_GETPID_IN_UNISTD_H 1
#define GPR_SUPPORT_CHANNELS_FROM_FD 1
#if defined(__has_include)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif /* __has_include(<android/ndk-version.h>) */
#endif /* defined(__has_include) */
#include <linux/version.h>
#elif defined(__linux__)
#define GPR_PLATFORM_STRING "linux"
#ifndef _BSD_SOURCE

@ -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__"],
)
@ -2381,9 +2378,11 @@ grpc_cc_library(
hdrs = ["lib/event_engine/utils.h"],
external_deps = [
"absl/log:check",
"absl/status:statusor",
"absl/strings",
],
deps = [
"notification",
"time",
"//:event_engine_base_hdrs",
"//:gpr_platform",
@ -7199,33 +7198,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 = [
@ -7688,8 +7660,11 @@ grpc_cc_library(
"connection_quota",
"error",
"error_utils",
"event_engine_common",
"event_engine_extensions",
"event_engine_query_extensions",
"event_engine_tcp_socket_utils",
"event_engine_utils",
"grpc_insecure_credentials",
"handshaker_registry",
"iomgr_fwd",
@ -8040,6 +8015,8 @@ grpc_cc_library(
"chaotic_good_transport",
"context",
"event_engine_context",
"event_engine_extensions",
"event_engine_query_extensions",
"for_each",
"grpc_promise_endpoint",
"if",
@ -8190,6 +8167,7 @@ grpc_cc_library(
"call_final_info",
"call_state",
"dump_args",
"for_each",
"if",
"latch",
"map",

@ -57,8 +57,19 @@ static backup_poller* g_poller = nullptr; // guarded by g_poller_mu
// treated as const.
static grpc_core::Duration g_poll_interval =
grpc_core::Duration::Milliseconds(DEFAULT_POLL_INTERVAL_MS);
// TODO(hork): delete the backup poller when EventEngine is rolled out
// everywhere.
static bool g_backup_polling_disabled;
void grpc_client_channel_global_init_backup_polling() {
// Disable backup polling if EventEngine is used everywhere.
g_backup_polling_disabled = grpc_core::IsEventEngineClientEnabled() &&
grpc_core::IsEventEngineListenerEnabled() &&
grpc_core::IsEventEngineDnsEnabled();
if (g_backup_polling_disabled) {
return;
}
gpr_mu_init(&g_poller_mu);
int32_t poll_interval_ms =
grpc_core::ConfigVars::Get().ClientChannelBackupPollIntervalMs();
@ -146,7 +157,8 @@ static void g_poller_init_locked() {
void grpc_client_channel_start_backup_polling(
grpc_pollset_set* interested_parties) {
if (g_poll_interval == grpc_core::Duration::Zero() ||
if (g_backup_polling_disabled ||
g_poll_interval == grpc_core::Duration::Zero() ||
grpc_iomgr_run_in_background()) {
return;
}
@ -165,7 +177,8 @@ void grpc_client_channel_start_backup_polling(
void grpc_client_channel_stop_backup_polling(
grpc_pollset_set* interested_parties) {
if (g_poll_interval == grpc_core::Duration::Zero() ||
if (g_backup_polling_disabled ||
g_poll_interval == grpc_core::Duration::Zero() ||
grpc_iomgr_run_in_background()) {
return;
}

@ -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

@ -36,6 +36,8 @@
#include "src/core/ext/transport/chaotic_good/frame_header.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/lib/event_engine/event_engine_context.h"
#include "src/core/lib/event_engine/extensions/tcp_trace.h"
#include "src/core/lib/event_engine/query_extensions.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/loop.h"
#include "src/core/lib/promise/map.h"
@ -199,6 +201,15 @@ ChaoticGoodClientTransport::ChaoticGoodClientTransport(
->memory_quota()
->CreateMemoryAllocator("chaotic-good")),
outgoing_frames_(4) {
// Set up TCP tracer if enabled.
if (args.GetBool(GRPC_ARG_TCP_TRACING_ENABLED).value_or(false)) {
auto* epte = grpc_event_engine::experimental::QueryExtension<
grpc_event_engine::experimental::TcpTraceExtension>(
data_endpoint.GetEventEngineEndpoint().get());
if (epte != nullptr) {
epte->InitializeAndReturnTcpTracer();
}
}
auto transport = MakeRefCounted<ChaoticGoodTransport>(
std::move(control_endpoint), std::move(data_endpoint),
std::move(hpack_parser), std::move(hpack_encoder));
@ -255,6 +266,13 @@ uint32_t ChaoticGoodClientTransport::MakeStream(CallHandler call_handler) {
return stream_id;
}
namespace {
absl::Status BooleanSuccessToTransportError(bool success) {
return success ? absl::OkStatus()
: absl::UnavailableError("Transport closed.");
}
} // namespace
auto ChaoticGoodClientTransport::CallOutboundLoop(uint32_t stream_id,
CallHandler call_handler) {
auto send_fragment = [stream_id,
@ -262,13 +280,14 @@ auto ChaoticGoodClientTransport::CallOutboundLoop(uint32_t stream_id,
ClientFragmentFrame frame) mutable {
frame.stream_id = stream_id;
return Map(outgoing_frames.Send(std::move(frame)),
[](bool success) -> absl::Status {
if (!success) {
// Failed to send outgoing frame.
return absl::UnavailableError("Transport closed.");
}
return absl::OkStatus();
});
BooleanSuccessToTransportError);
};
auto send_fragment_acked = [stream_id,
outgoing_frames = outgoing_frames_.MakeSender()](
ClientFragmentFrame frame) mutable {
frame.stream_id = stream_id;
return Map(outgoing_frames.SendAcked(std::move(frame)),
BooleanSuccessToTransportError);
};
return GRPC_LATENT_SEE_PROMISE(
"CallOutboundLoop",
@ -285,7 +304,7 @@ auto ChaoticGoodClientTransport::CallOutboundLoop(uint32_t stream_id,
},
// Continuously send client frame with client to server messages.
ForEach(OutgoingMessages(call_handler),
[send_fragment, aligned_bytes = aligned_bytes_](
[send_fragment_acked, aligned_bytes = aligned_bytes_](
MessageHandle message) mutable {
ClientFragmentFrame frame;
// Construct frame header (flags, header_length and
@ -299,7 +318,7 @@ auto ChaoticGoodClientTransport::CallOutboundLoop(uint32_t stream_id,
CHECK_EQ((message_length + padding) % aligned_bytes, 0u);
frame.message = FragmentMessage(std::move(message), padding,
message_length);
return send_fragment(std::move(frame));
return send_fragment_acked(std::move(frame));
}),
[send_fragment]() mutable {
ClientFragmentFrame frame;

@ -124,6 +124,15 @@ auto ChaoticGoodServerTransport::MaybePushFragmentIntoCall(
});
}
namespace {
auto BooleanSuccessToTransportErrorCapturingInitiator(CallInitiator initiator) {
return [initiator = std::move(initiator)](bool success) {
return success ? absl::OkStatus()
: absl::UnavailableError("Transport closed.");
};
}
} // namespace
auto ChaoticGoodServerTransport::SendFragment(
ServerFragmentFrame frame, MpscSender<ServerFrame> outgoing_frames,
CallInitiator call_initiator) {
@ -132,13 +141,20 @@ auto ChaoticGoodServerTransport::SendFragment(
// Capture the call_initiator to ensure the underlying call spine is alive
// until the outgoing_frames.Send promise completes.
return Map(outgoing_frames.Send(std::move(frame)),
[call_initiator](bool success) -> absl::Status {
if (!success) {
// Failed to send outgoing frame.
return absl::UnavailableError("Transport closed.");
}
return absl::OkStatus();
});
BooleanSuccessToTransportErrorCapturingInitiator(
std::move(call_initiator)));
}
auto ChaoticGoodServerTransport::SendFragmentAcked(
ServerFragmentFrame frame, MpscSender<ServerFrame> outgoing_frames,
CallInitiator call_initiator) {
GRPC_TRACE_LOG(chaotic_good, INFO)
<< "CHAOTIC_GOOD: SendFragmentAcked: frame=" << frame.ToString();
// Capture the call_initiator to ensure the underlying call spine is alive
// until the outgoing_frames.Send promise completes.
return Map(outgoing_frames.SendAcked(std::move(frame)),
BooleanSuccessToTransportErrorCapturingInitiator(
std::move(call_initiator)));
}
auto ChaoticGoodServerTransport::SendCallBody(
@ -165,7 +181,8 @@ auto ChaoticGoodServerTransport::SendCallBody(
frame.message =
FragmentMessage(std::move(message), padding, message_length);
frame.stream_id = stream_id;
return SendFragment(std::move(frame), outgoing_frames, call_initiator);
return SendFragmentAcked(std::move(frame), outgoing_frames,
call_initiator);
});
}

@ -111,6 +111,9 @@ class ChaoticGoodServerTransport final : public ServerTransport {
static auto SendFragment(ServerFragmentFrame frame,
MpscSender<ServerFrame> outgoing_frames,
CallInitiator call_initiator);
static auto SendFragmentAcked(ServerFragmentFrame frame,
MpscSender<ServerFrame> outgoing_frames,
CallInitiator call_initiator);
auto CallOutboundLoop(uint32_t stream_id, CallInitiator call_initiator);
auto OnTransportActivityDone(absl::string_view activity);
auto TransportReadLoop(RefCountedPtr<ChaoticGoodTransport> transport);

@ -59,6 +59,9 @@
#include "src/core/lib/event_engine/channel_args_endpoint_config.h"
#include "src/core/lib/event_engine/extensions/supports_fd.h"
#include "src/core/lib/event_engine/query_extensions.h"
#include "src/core/lib/event_engine/resolved_address_internal.h"
#include "src/core/lib/event_engine/tcp_socket_utils.h"
#include "src/core/lib/event_engine/utils.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/event_engine_shims/endpoint.h"
@ -113,7 +116,8 @@ using AcceptorPtr = std::unique_ptr<grpc_tcp_server_acceptor, AcceptorDeleter>;
class Chttp2ServerListener : public Server::ListenerInterface {
public:
static grpc_error_handle Create(Server* server, grpc_resolved_address* addr,
static grpc_error_handle Create(Server* server,
const EventEngine::ResolvedAddress& addr,
const ChannelArgs& args,
Chttp2ServerArgsModifier args_modifier,
int* port_num);
@ -627,8 +631,10 @@ void Chttp2ServerListener::ActiveConnection::SendGoAway() {
}
if (transport != nullptr) {
grpc_transport_op* op = grpc_make_transport_op(nullptr);
op->goaway_error =
GRPC_ERROR_CREATE("Server is stopping to serve requests.");
// Set an HTTP2 error of NO_ERROR to do graceful GOAWAYs.
op->goaway_error = grpc_error_set_int(
GRPC_ERROR_CREATE("Server is stopping to serve requests."),
StatusIntProperty::kHttp2Error, GRPC_HTTP2_NO_ERROR);
transport->PerformOp(op);
}
}
@ -701,8 +707,9 @@ void Chttp2ServerListener::ActiveConnection::OnDrainGraceTimeExpiry() {
//
grpc_error_handle Chttp2ServerListener::Create(
Server* server, grpc_resolved_address* addr, const ChannelArgs& args,
Chttp2ServerArgsModifier args_modifier, int* port_num) {
Server* server, const EventEngine::ResolvedAddress& addr,
const ChannelArgs& args, Chttp2ServerArgsModifier args_modifier,
int* port_num) {
// Create Chttp2ServerListener.
OrphanablePtr<Chttp2ServerListener> listener =
MakeOrphanable<Chttp2ServerListener>(server, args, args_modifier,
@ -714,18 +721,24 @@ grpc_error_handle Chttp2ServerListener::Create(
&listener->tcp_server_shutdown_complete_, ChannelArgsEndpointConfig(args),
OnAccept, listener.get(), &listener->tcp_server_);
if (!error.ok()) return error;
// TODO(yijiem): remove this conversion when we remove all
// grpc_resolved_address usages.
grpc_resolved_address iomgr_addr =
grpc_event_engine::experimental::CreateGRPCResolvedAddress(addr);
if (listener->config_fetcher_ != nullptr) {
listener->resolved_address_ = *addr;
listener->resolved_address_ = iomgr_addr;
// TODO(yashykt): Consider binding so as to be able to return the port
// number.
} else {
error = grpc_tcp_server_add_port(listener->tcp_server_, addr, port_num);
error =
grpc_tcp_server_add_port(listener->tcp_server_, &iomgr_addr, port_num);
if (!error.ok()) return error;
}
// Create channelz node.
if (args.GetBool(GRPC_ARG_ENABLE_CHANNELZ)
.value_or(GRPC_ENABLE_CHANNELZ_DEFAULT)) {
auto string_address = grpc_sockaddr_to_uri(addr);
auto string_address =
grpc_event_engine::experimental::ResolvedAddressToString(addr);
if (!string_address.ok()) {
return GRPC_ERROR_CREATE(string_address.status().ToString());
}
@ -955,37 +968,68 @@ grpc_error_handle Chttp2ServerAddPort(Server* server, const char* addr,
args_modifier);
}
*port_num = -1;
absl::StatusOr<std::vector<grpc_resolved_address>> resolved_or;
absl::StatusOr<std::vector<grpc_resolved_address>> resolved;
absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> results =
std::vector<EventEngine::ResolvedAddress>();
std::vector<grpc_error_handle> error_list;
std::string parsed_addr = URI::PercentDecode(addr);
absl::string_view parsed_addr_unprefixed{parsed_addr};
// Using lambda to avoid use of goto.
grpc_error_handle error = [&]() {
grpc_error_handle error;
// TODO(ladynana, yijiem): this code does not handle address URIs correctly:
// it's parsing `unix://foo/bar` as path `/foo/bar` when it should be
// parsing it as authority `foo` and path `/bar`. Also add API documentation
// on the valid URIs that grpc_server_add_http2_port accepts.
if (absl::ConsumePrefix(&parsed_addr_unprefixed, kUnixUriPrefix)) {
resolved_or = grpc_resolve_unix_domain_address(parsed_addr_unprefixed);
resolved = grpc_resolve_unix_domain_address(parsed_addr_unprefixed);
GRPC_RETURN_IF_ERROR(resolved.status());
} else if (absl::ConsumePrefix(&parsed_addr_unprefixed,
kUnixAbstractUriPrefix)) {
resolved_or =
resolved =
grpc_resolve_unix_abstract_domain_address(parsed_addr_unprefixed);
GRPC_RETURN_IF_ERROR(resolved.status());
} else if (absl::ConsumePrefix(&parsed_addr_unprefixed, kVSockUriPrefix)) {
resolved_or = grpc_resolve_vsock_address(parsed_addr_unprefixed);
resolved = grpc_resolve_vsock_address(parsed_addr_unprefixed);
GRPC_RETURN_IF_ERROR(resolved.status());
} else {
resolved_or =
GetDNSResolver()->LookupHostnameBlocking(parsed_addr, "https");
if (IsEventEngineDnsNonClientChannelEnabled()) {
absl::StatusOr<std::unique_ptr<EventEngine::DNSResolver>> ee_resolver =
args.GetObjectRef<EventEngine>()->GetDNSResolver(
EventEngine::DNSResolver::ResolverOptions());
GRPC_RETURN_IF_ERROR(ee_resolver.status());
results = grpc_event_engine::experimental::LookupHostnameBlocking(
ee_resolver->get(), parsed_addr, "https");
} else {
// TODO(yijiem): Remove this after event_engine_dns_non_client_channel
// is fully enabled.
absl::StatusOr<std::vector<grpc_resolved_address>> iomgr_results =
GetDNSResolver()->LookupHostnameBlocking(parsed_addr, "https");
GRPC_RETURN_IF_ERROR(iomgr_results.status());
for (const auto& addr : *iomgr_results) {
results->push_back(
grpc_event_engine::experimental::CreateResolvedAddress(addr));
}
}
}
if (!resolved_or.ok()) {
return absl_status_to_grpc_error(resolved_or.status());
if (resolved.ok()) {
for (const auto& addr : *resolved) {
results->push_back(
grpc_event_engine::experimental::CreateResolvedAddress(addr));
}
}
GRPC_RETURN_IF_ERROR(results.status());
// Create a listener for each resolved address.
for (auto& addr : *resolved_or) {
for (EventEngine::ResolvedAddress& addr : *results) {
// If address has a wildcard port (0), use the same port as a previous
// listener.
if (*port_num != -1 && grpc_sockaddr_get_port(&addr) == 0) {
grpc_sockaddr_set_port(&addr, *port_num);
if (*port_num != -1 &&
grpc_event_engine::experimental::ResolvedAddressGetPort(addr) == 0) {
grpc_event_engine::experimental::ResolvedAddressSetPort(addr,
*port_num);
}
int port_temp = -1;
error = Chttp2ServerListener::Create(server, &addr, args, args_modifier,
error = Chttp2ServerListener::Create(server, addr, args, args_modifier,
&port_temp);
if (!error.ok()) {
error_list.push_back(error);
@ -997,17 +1041,17 @@ grpc_error_handle Chttp2ServerAddPort(Server* server, const char* addr,
}
}
}
if (error_list.size() == resolved_or->size()) {
if (error_list.size() == results->size()) {
std::string msg = absl::StrFormat(
"No address added out of total %" PRIuPTR " resolved for '%s'",
resolved_or->size(), addr);
results->size(), addr);
return GRPC_ERROR_CREATE_REFERENCING(msg.c_str(), error_list.data(),
error_list.size());
} else if (!error_list.empty()) {
std::string msg = absl::StrFormat(
"Only %" PRIuPTR " addresses added out of total %" PRIuPTR
" resolved",
resolved_or->size() - error_list.size(), resolved_or->size());
std::string msg =
absl::StrFormat("Only %" PRIuPTR
" addresses added out of total %" PRIuPTR " resolved",
results->size() - error_list.size(), results->size());
error = GRPC_ERROR_CREATE_REFERENCING(msg.c_str(), error_list.data(),
error_list.size());
LOG(INFO) << "WARNING: " << StatusToString(error);

@ -68,6 +68,8 @@
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/telemetry/call_tracer.h"
#include "src/core/telemetry/stats.h"
#include "src/core/telemetry/stats_data.h"
#include "src/core/util/random_early_detection.h"
#include "src/core/util/ref_counted_ptr.h"
#include "src/core/util/status_helper.h"
@ -642,6 +644,18 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
GRPC_HTTP2_REFUSED_STREAM, nullptr));
grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_RST_STREAM);
return init_header_skip_frame_parser(t, priority_type, is_eoh);
} else if (grpc_core::IsRqFastRejectEnabled() &&
GPR_UNLIKELY(t->memory_owner.IsMemoryPressureHigh())) {
// We have more streams allocated than we'd like, so apply some pushback
// by refusing this stream.
grpc_core::global_stats().IncrementRqCallsRejected();
++t->num_pending_induced_frames;
grpc_slice_buffer_add(
&t->qbuf,
grpc_chttp2_rst_stream_create(t->incoming_stream_id,
GRPC_HTTP2_ENHANCE_YOUR_CALM, nullptr));
grpc_chttp2_initiate_write(t, GRPC_CHTTP2_INITIATE_WRITE_RST_STREAM);
return init_header_skip_frame_parser(t, priority_type, is_eoh);
} else if (GPR_UNLIKELY(
t->max_concurrent_streams_overload_protection &&
t->streams_allocated.load(std::memory_order_relaxed) >

@ -107,8 +107,11 @@ class PosixEngineListenerImpl
}
ListenerSocketsContainer::ListenerSocket& Socket() { return socket_; }
~AsyncConnectionAcceptor() {
// If uds socket, unlink it so that the corresponding file is deleted.
UnlinkIfUnixDomainSocket(*socket_.sock.LocalAddress());
auto address = socket_.sock.LocalAddress();
if (address.ok()) {
// If uds socket, unlink it so that the corresponding file is deleted.
UnlinkIfUnixDomainSocket(*address);
}
handle_->OrphanHandle(nullptr, nullptr, "");
delete notify_on_accept_;
}

@ -48,6 +48,9 @@ EventEngine::ResolvedAddress CreateResolvedAddress(
grpc_resolved_address CreateGRPCResolvedAddress(
const EventEngine::ResolvedAddress& ra) {
static_assert(
GRPC_MAX_SOCKADDR_SIZE == EventEngine::ResolvedAddress::MAX_SIZE_BYTES,
"size should match");
grpc_resolved_address grpc_addr;
memset(&grpc_addr, 0, sizeof(grpc_resolved_address));
memcpy(grpc_addr.addr, ra.address(), ra.size());

@ -20,6 +20,7 @@
#include <algorithm>
#include "absl/strings/str_cat.h"
#include "src/core/util/notification.h"
#include "src/core/util/time.h"
namespace grpc_event_engine {
@ -38,5 +39,20 @@ grpc_core::Timestamp ToTimestamp(grpc_core::Timestamp now,
grpc_core::Duration::Milliseconds(1);
}
absl::StatusOr<std::vector<EventEngine::ResolvedAddress>>
LookupHostnameBlocking(EventEngine::DNSResolver* dns_resolver,
absl::string_view name, absl::string_view default_port) {
absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> results;
grpc_core::Notification done;
dns_resolver->LookupHostname(
[&](absl::StatusOr<std::vector<EventEngine::ResolvedAddress>> addresses) {
results = std::move(addresses);
done.Notify();
},
name, default_port);
done.WaitForNotification();
return results;
}
} // namespace experimental
} // namespace grpc_event_engine

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save