libbinder: delete dead server objects

We can do more active cleanup, and we can do kinder cleanup, but for now
fix leaks (future considerations/TODOs left in code).

Bug: 185167543
Test: binderRpcTest
Change-Id: Ide06476aefd72cbc46ba5fba095244a5448e493b
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 786e2db..aaebb23 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -216,4 +216,16 @@
     return true;
 }
 
+void RpcServer::onSessionTerminating(const sp<RpcSession>& session) {
+    auto id = session->mId;
+    LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
+    LOG_RPC_DETAIL("Dropping session %d", *id);
+
+    std::lock_guard<std::mutex> _l(mLock);
+    auto it = mSessions.find(*id);
+    LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %d", *id);
+    LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %d", *id);
+    (void)mSessions.erase(it);
+}
+
 } // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 09ec20d..bf998c1 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -24,6 +24,7 @@
 #include <string_view>
 
 #include <binder/Parcel.h>
+#include <binder/RpcServer.h>
 #include <binder/Stability.h>
 #include <utils/String8.h>
 
@@ -168,6 +169,22 @@
                         "bad state: connection object guaranteed to be in list");
 }
 
+void RpcSession::terminateLocked() {
+    // TODO(b/185167543):
+    // - kindly notify other side of the connection of termination (can't be
+    // locked)
+    // - prevent new client/servers from being added
+    // - stop all threads which are currently reading/writing
+    // - terminate RpcState?
+
+    if (mTerminated) return;
+
+    sp<RpcServer> server = mForServer.promote();
+    if (server) {
+        server->onSessionTerminating(sp<RpcSession>::fromExisting(this));
+    }
+}
+
 wp<RpcServer> RpcSession::server() {
     return mForServer;
 }
@@ -264,6 +281,9 @@
     std::lock_guard<std::mutex> _l(mMutex);
     if (auto it = std::find(mServers.begin(), mServers.end(), connection); it != mServers.end()) {
         mServers.erase(it);
+        if (mServers.size() == 0) {
+            terminateLocked();
+        }
         return true;
     }
     return false;
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index c98151d..8c9ba00 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -109,6 +109,10 @@
 
     ~RpcServer();
 
+    // internal use only
+
+    void onSessionTerminating(const sp<RpcSession>& session);
+
 private:
     friend sp<RpcServer>;
     RpcServer();
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 3f58b2c..d49d48d 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -118,6 +118,7 @@
 
     void startThread(base::unique_fd client);
     void join(base::unique_fd client);
+    void terminateLocked();
 
     struct RpcConnection : public RefBase {
         base::unique_fd fd;
@@ -196,6 +197,7 @@
     // TODO(b/185167543): allow sharing between different sessions in a
     // process? (or combine with mServers)
     std::map<std::thread::id, std::thread> mThreads;
+    bool mTerminated = false;
 };
 
 } // namespace android