blob: bbcf07834977303362fc02c95aa5666bbca3c52e [file] [log] [blame]
// 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 "src/core/ext/transport/binder/server/binder_server.h"
#ifndef GRPC_NO_BINDER
#include <memory>
#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include <grpc/grpc.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/surface/server.h"
#include "src/core/lib/transport/error_utils.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) {
gpr_log(GPR_ERROR, "Cannot find endpoint binder with connection id = %s",
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 { delete this; }
~BinderServerListener() override {
ExecCtx::Get()->Flush();
if (on_destroy_done_) {
ExecCtx::Run(DEBUG_LOCATION, on_destroy_done_, GRPC_ERROR_NONE);
ExecCtx::Get()->Flush();
}
grpc_remove_endpoint_binder(addr_);
}
private:
absl::Status OnSetupTransport(transaction_code_t code,
grpc_binder::ReadableParcel* parcel, int uid) {
grpc_core::ExecCtx exec_ctx;
if (grpc_binder::BinderTransportTxCode(code) !=
grpc_binder::BinderTransportTxCode::SETUP_TRANSPORT) {
return absl::InvalidArgumentError("Not a SETUP_TRANSPORT request");
}
gpr_log(GPR_ERROR, "calling uid = %d", 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;
}
gpr_log(GPR_INFO, "version = %d", version);
// TODO(waynetu): Check supported version.
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().
grpc_transport* server_transport = grpc_create_binder_transport_server(
std::move(client_binder), security_policy_);
GPR_ASSERT(server_transport);
grpc_channel_args* args = grpc_channel_args_copy(server_->channel_args());
grpc_error_handle error = server_->SetupTransport(server_transport, nullptr,
args, nullptr, nullptr);
grpc_channel_args_destroy(args);
return grpc_error_to_absl_status(error);
}
Server* server_;
grpc_closure* on_destroy_done_ = nullptr;
std::string addr_;
BinderTxReceiverFactory factory_;
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());
grpc_core::Server* core_server = server->core_server.get();
core_server->AddListener(
grpc_core::OrphanablePtr<grpc_core::Server::ListenerInterface>(
new grpc_core::BinderServerListener(
core_server, conn_id, std::move(factory), security_policy)));
return true;
}
} // namespace grpc_core
#endif