Add RpcServer::shutdown.
The function terminates any existing execution of join().
After this CL, join() is only allowed to be called in one thread.
Test: binderLibTest
Change-Id: I5f1abbb39ee42a8f94b7394a702a152701537e7e
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index a96deb5..fb0ffdb 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -40,6 +40,8 @@
#include "../RpcState.h" // for debugging
#include "../vm_sockets.h" // for VMADDR_*
+using namespace std::chrono_literals;
+
namespace android {
TEST(BinderRpcParcel, EntireParcelFormatted) {
@@ -970,6 +972,54 @@
INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
::testing::Combine(::testing::Bool(), ::testing::Bool()));
+class OneOffSignal {
+public:
+ // If notify() was previously called, or is called within |duration|, return true; else false.
+ template <typename R, typename P>
+ bool wait(std::chrono::duration<R, P> duration) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ return mCv.wait_for(lock, duration, [this] { return mValue; });
+ }
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mValue = true;
+ lock.unlock();
+ mCv.notify_all();
+ }
+
+private:
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mValue = false;
+};
+
+TEST(BinderRpc, Shutdown) {
+ auto addr = allocateSocketAddress();
+ unlink(addr.c_str());
+ auto server = RpcServer::make();
+ server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+ ASSERT_TRUE(server->setupUnixDomainServer(addr.c_str()));
+ auto joinEnds = std::make_shared<OneOffSignal>();
+
+ // If things are broken and the thread never stops, don't block other tests. Because the thread
+ // may run after the test finishes, it must not access the stack memory of the test. Hence,
+ // shared pointers are passed.
+ std::thread([server, joinEnds] {
+ server->join();
+ joinEnds->notify();
+ }).detach();
+
+ bool shutdown = false;
+ for (int i = 0; i < 10 && !shutdown; i++) {
+ usleep(300 * 1000); // 300ms; total 3s
+ if (server->shutdown()) shutdown = true;
+ }
+ ASSERT_TRUE(shutdown) << "server->shutdown() never returns true";
+
+ ASSERT_TRUE(joinEnds->wait(2s))
+ << "After server->shutdown() returns true, join() did not stop after 2s";
+}
+
} // namespace android
int main(int argc, char** argv) {