libbinder: handle ExclusiveSocket failure

Fixes TODO here and adds test case for fatal abort which shouldn't be
allowed to kill a server.

Bug: 167966510
Test: binderRpcTest
Change-Id: Id38049eda5c9199a11101d0ff0b7790a476afc44
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 2a230d2..a759ae3 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -104,12 +104,18 @@
 }
 
 sp<IBinder> RpcSession::getRootObject() {
-    ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
+    ExclusiveConnection connection;
+    status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                                ConnectionUse::CLIENT, &connection);
+    if (status != OK) return nullptr;
     return state()->getRootObject(connection.fd(), sp<RpcSession>::fromExisting(this));
 }
 
 status_t RpcSession::getRemoteMaxThreads(size_t* maxThreads) {
-    ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
+    ExclusiveConnection connection;
+    status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                                ConnectionUse::CLIENT, &connection);
+    if (status != OK) return status;
     return state()->getMaxThreads(connection.fd(), sp<RpcSession>::fromExisting(this), maxThreads);
 }
 
@@ -133,16 +139,22 @@
 
 status_t RpcSession::transact(const sp<IBinder>& binder, uint32_t code, const Parcel& data,
                               Parcel* reply, uint32_t flags) {
-    ExclusiveConnection connection(sp<RpcSession>::fromExisting(this),
-                                   (flags & IBinder::FLAG_ONEWAY) ? ConnectionUse::CLIENT_ASYNC
-                                                                  : ConnectionUse::CLIENT);
+    ExclusiveConnection connection;
+    status_t status =
+            ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                      (flags & IBinder::FLAG_ONEWAY) ? ConnectionUse::CLIENT_ASYNC
+                                                                     : ConnectionUse::CLIENT,
+                                      &connection);
+    if (status != OK) return status;
     return state()->transact(connection.fd(), binder, code, data,
                              sp<RpcSession>::fromExisting(this), reply, flags);
 }
 
 status_t RpcSession::sendDecStrong(const RpcAddress& address) {
-    ExclusiveConnection connection(sp<RpcSession>::fromExisting(this),
-                                   ConnectionUse::CLIENT_REFCOUNT);
+    ExclusiveConnection connection;
+    status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                                ConnectionUse::CLIENT_REFCOUNT, &connection);
+    if (status != OK) return status;
     return state()->sendDecStrong(connection.fd(), sp<RpcSession>::fromExisting(this), address);
 }
 
@@ -208,9 +220,12 @@
 
     int32_t id;
 
-    ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
-    status_t status =
-            state()->getSessionId(connection.fd(), sp<RpcSession>::fromExisting(this), &id);
+    ExclusiveConnection connection;
+    status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                                ConnectionUse::CLIENT, &connection);
+    if (status != OK) return status;
+
+    status = state()->getSessionId(connection.fd(), sp<RpcSession>::fromExisting(this), &id);
     if (status != OK) return status;
 
     LOG_RPC_DETAIL("RpcSession %p has id %d", this, id);
@@ -493,13 +508,16 @@
     return false;
 }
 
-RpcSession::ExclusiveConnection::ExclusiveConnection(const sp<RpcSession>& session,
-                                                     ConnectionUse use)
-      : mSession(session) {
-    pid_t tid = gettid();
-    std::unique_lock<std::mutex> _l(mSession->mMutex);
+status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, ConnectionUse use,
+                                               ExclusiveConnection* connection) {
+    connection->mSession = session;
+    connection->mConnection = nullptr;
+    connection->mReentrant = false;
 
-    mSession->mWaitingThreads++;
+    pid_t tid = gettid();
+    std::unique_lock<std::mutex> _l(session->mMutex);
+
+    session->mWaitingThreads++;
     while (true) {
         sp<RpcConnection> exclusive;
         sp<RpcConnection> available;
@@ -507,8 +525,8 @@
         // CHECK FOR DEDICATED CLIENT SOCKET
         //
         // A server/looper should always use a dedicated connection if available
-        findConnection(tid, &exclusive, &available, mSession->mClientConnections,
-                       mSession->mClientConnectionsOffset);
+        findConnection(tid, &exclusive, &available, session->mClientConnections,
+                       session->mClientConnectionsOffset);
 
         // WARNING: this assumes a server cannot request its client to send
         // a transaction, as mServerConnections is excluded below.
@@ -521,8 +539,8 @@
         // command. So, we move to considering the second available thread
         // for subsequent calls.
         if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
-            mSession->mClientConnectionsOffset =
-                    (mSession->mClientConnectionsOffset + 1) % mSession->mClientConnections.size();
+            session->mClientConnectionsOffset =
+                    (session->mClientConnectionsOffset + 1) % session->mClientConnections.size();
         }
 
         // USE SERVING SOCKET (for nested transaction)
@@ -530,35 +548,36 @@
         // asynchronous calls cannot be nested
         if (use != ConnectionUse::CLIENT_ASYNC) {
             // server connections are always assigned to a thread
-            findConnection(tid, &exclusive, nullptr /*available*/, mSession->mServerConnections,
+            findConnection(tid, &exclusive, nullptr /*available*/, session->mServerConnections,
                            0 /* index hint */);
         }
 
         // if our thread is already using a connection, prioritize using that
         if (exclusive != nullptr) {
-            mConnection = exclusive;
-            mReentrant = true;
+            connection->mConnection = exclusive;
+            connection->mReentrant = true;
             break;
         } else if (available != nullptr) {
-            mConnection = available;
-            mConnection->exclusiveTid = tid;
+            connection->mConnection = available;
+            connection->mConnection->exclusiveTid = tid;
             break;
         }
 
-        // TODO(b/185167543): this should return an error, rather than crash a
-        // server
-        // in regular binder, this would usually be a deadlock :)
-        LOG_ALWAYS_FATAL_IF(mSession->mClientConnections.size() == 0,
-                            "Session has no client connections. This is required for an RPC server "
-                            "to make any non-nested (e.g. oneway or on another thread) calls. "
-                            "Use: %d. Server connections: %zu",
-                            static_cast<int>(use), mSession->mServerConnections.size());
+        if (session->mClientConnections.size() == 0) {
+            ALOGE("Session has no client connections. This is required for an RPC server to make "
+                  "any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
+                  "connections: %zu",
+                  static_cast<int>(use), session->mServerConnections.size());
+            return WOULD_BLOCK;
+        }
 
         LOG_RPC_DETAIL("No available connections (have %zu clients and %zu servers). Waiting...",
-                       mSession->mClientConnections.size(), mSession->mServerConnections.size());
-        mSession->mAvailableConnectionCv.wait(_l);
+                       session->mClientConnections.size(), session->mServerConnections.size());
+        session->mAvailableConnectionCv.wait(_l);
     }
-    mSession->mWaitingThreads--;
+    session->mWaitingThreads--;
+
+    return OK;
 }
 
 void RpcSession::ExclusiveConnection::findConnection(pid_t tid, sp<RpcConnection>* exclusive,
@@ -592,7 +611,7 @@
     // reentrant use of a connection means something less deep in the call stack
     // is using this fd, and it retains the right to it. So, we don't give up
     // exclusive ownership, and no thread is freed.
-    if (!mReentrant) {
+    if (!mReentrant && mConnection != nullptr) {
         std::unique_lock<std::mutex> _l(mSession->mMutex);
         mConnection->exclusiveTid = std::nullopt;
         if (mSession->mWaitingThreads > 0) {