libbinder: RpcServer - shutdown connection threads
Re-use FdTrigger to shutdown connection threads.
Coming next - shutting down sessions as well!
Bug: 185167543
Test: binderRpcTest, binder_rpc_fuzzer
Change-Id: I238f1e2a5f69fdec09ac8b3afc484ab8639852fa
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 50b0465..540c346 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -184,10 +184,18 @@
bool RpcServer::shutdown() {
std::unique_lock<std::mutex> _l(mLock);
- if (mShutdownTrigger == nullptr) return false;
+ if (mShutdownTrigger == nullptr) {
+ LOG_RPC_DETAIL("Cannot shutdown. No shutdown trigger installed.");
+ return false;
+ }
mShutdownTrigger->trigger();
- while (mJoinThreadRunning) mShutdownCv.wait(_l);
+ while (mJoinThreadRunning || !mConnectingThreads.empty()) {
+ ALOGI("Waiting for RpcServer to shut down. Join thread running: %d, Connecting threads: "
+ "%zu",
+ mJoinThreadRunning, mConnectingThreads.size());
+ mShutdownCv.wait(_l);
+ }
// At this point, we know join() is about to exit, but the thread that calls
// join() may not have exited yet.
@@ -222,17 +230,21 @@
void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd) {
// TODO(b/183988761): cannot trust this simple ID
LOG_ALWAYS_FATAL_IF(!server->mAgreedExperimental, "no!");
- bool idValid = true;
+
+ // mShutdownTrigger can only be cleared once connection threads have joined.
+ // It must be set before this thread is started
+ LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
+
int32_t id;
- if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
- ALOGE("Could not read ID from fd %d", clientFd.get());
- idValid = false;
+ bool idValid = server->mShutdownTrigger->interruptableRecv(clientFd.get(), &id, sizeof(id));
+ if (!idValid) {
+ ALOGE("Failed to read ID for client connecting to RPC server.");
}
std::thread thisThread;
sp<RpcSession> session;
{
- std::lock_guard<std::mutex> _l(server->mLock);
+ std::unique_lock<std::mutex> _l(server->mLock);
auto threadId = server->mConnectingThreads.find(std::this_thread::get_id());
LOG_ALWAYS_FATAL_IF(threadId == server->mConnectingThreads.end(),
@@ -241,6 +253,16 @@
ScopeGuard detachGuard = [&]() { thisThread.detach(); };
server->mConnectingThreads.erase(threadId);
+ // TODO(b/185167543): we currently can't disable this because we don't
+ // shutdown sessions as well, only the server itself. So, we need to
+ // keep this separate from the detachGuard, since we temporarily want to
+ // give a notification even when we pass ownership of the thread to
+ // a session.
+ ScopeGuard threadLifetimeGuard = [&]() {
+ _l.unlock();
+ server->mShutdownCv.notify_all();
+ };
+
if (!idValid) {
return;
}