Add RpcServer::start()

start() starts a thread that runs join() in the background.

Because the thread can now be owned by RpcServer, shutdown() ensures
the thread is properly cleaned up.

Test: binderRpcTest
Bug: 182914638

Change-Id: I570d3d852e9eb4f6064dce934a2fdb3bc8f210f7
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 73facc1..50b0465 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -128,6 +128,17 @@
     return ret;
 }
 
+static void joinRpcServer(sp<RpcServer>&& thiz) {
+    thiz->join();
+}
+
+void RpcServer::start() {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    std::lock_guard<std::mutex> _l(mLock);
+    LOG_ALWAYS_FATAL_IF(mJoinThread.get(), "Already started!");
+    mJoinThread = std::make_unique<std::thread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
+}
+
 void RpcServer::join() {
     LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
 
@@ -178,6 +189,17 @@
     mShutdownTrigger->trigger();
     while (mJoinThreadRunning) mShutdownCv.wait(_l);
 
+    // At this point, we know join() is about to exit, but the thread that calls
+    // join() may not have exited yet.
+    // If RpcServer owns the join thread (aka start() is called), make sure the thread exits;
+    // otherwise ~thread() may call std::terminate(), which may crash the process.
+    // If RpcServer does not own the join thread (aka join() is called directly),
+    // then the owner of RpcServer is responsible for cleaning up that thread.
+    if (mJoinThread.get()) {
+        mJoinThread->join();
+        mJoinThread.reset();
+    }
+
     mShutdownTrigger = nullptr;
     return true;
 }
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index f76ecc2..50770f1 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -117,6 +117,11 @@
     sp<IBinder> getRootObject();
 
     /**
+     * Runs join() in a background thread. Immediately returns.
+     */
+    void start();
+
+    /**
      * You must have at least one client session before calling this.
      *
      * If a client needs to actively terminate join, call shutdown() in a separate thread.
@@ -159,12 +164,13 @@
     base::unique_fd mServer; // socket we are accepting sessions on
 
     std::mutex mLock; // for below
+    std::unique_ptr<std::thread> mJoinThread;
+    bool mJoinThreadRunning = false;
     std::map<std::thread::id, std::thread> mConnectingThreads;
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
     std::map<int32_t, sp<RpcSession>> mSessions;
     int32_t mSessionIdCounter = 0;
-    bool mJoinThreadRunning = false;
     std::unique_ptr<RpcSession::FdTrigger> mShutdownTrigger;
     std::condition_variable mShutdownCv;
 };