libbinder: ProcessState warn on forked
Reasonably common error, when people's programs are crashing, because
libbinder does not support forking (and supporting forking is really
complicated and error prone in multithreaded processes:
pthread_atfork documentation states this
The intent of pthread_atfork() was to provide a mechanism
whereby the application (or a library) could ensure that
mutexes and other process and thread state would be restored
to a consistent state. In practice, this task is generally
too difficult to be practicable.
specifically, in libbinder, we would have to:
- get all of the libbinder-related locks
- make sure the kernel driver can handle forking (or open a new
binder fd by reinstantiating ProcessState)
- (actual difficulty here) make sure we can capture and release
application-specific locks - in a multithreaded process,
anything could be going on
So, we don't want to take on the complexity of supporting it).
Instead now, we install a pthread_atfork handler which marks the
ProcessState as invalid in the child process. If code tries to access
ProcessState after forking, then it will throw an error (future: abort).
Note: forking and then using non-binder things, such as what installd
and vold does, is okay.
Bug: 202289725
Test: boot and check logs (none)
Change-Id: I18638a3190ed2ea23945413c2e5ab15d7094d0b0
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 94b2806..e2ab515 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -89,13 +89,23 @@
return init(nullptr, false /*requireDefault*/);
}
+[[clang::no_destroy]] static sp<ProcessState> gProcess;
+[[clang::no_destroy]] static std::mutex gProcessMutex;
+
+static void verifyNotForked(bool forked) {
+ if (forked) {
+ ALOGE("libbinder does not support being forked");
+ }
+}
+
sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
{
- [[clang::no_destroy]] static sp<ProcessState> gProcess;
- [[clang::no_destroy]] static std::mutex gProcessMutex;
if (driver == nullptr) {
std::lock_guard<std::mutex> l(gProcessMutex);
+ if (gProcess) {
+ verifyNotForked(gProcess->mForked);
+ }
return gProcess;
}
@@ -106,6 +116,14 @@
driver = "/dev/binder";
}
+ // we must install these before instantiating the gProcess object,
+ // otherwise this would race with creating it, and there could be the
+ // possibility of an invalid gProcess object forked by another thread
+ // before these are installed
+ int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
+ ProcessState::childPostFork);
+ LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
+
std::lock_guard<std::mutex> l(gProcessMutex);
gProcess = sp<ProcessState>::make(driver);
});
@@ -119,6 +137,7 @@
gProcess->getDriverName().c_str(), driver);
}
+ verifyNotForked(gProcess->mForked);
return gProcess;
}
@@ -137,6 +156,24 @@
return context;
}
+void ProcessState::onFork() {
+ // make sure another thread isn't currently retrieving ProcessState
+ gProcessMutex.lock();
+}
+
+void ProcessState::parentPostFork() {
+ gProcessMutex.unlock();
+}
+
+void ProcessState::childPostFork() {
+ // another thread might call fork before gProcess is instantiated, but after
+ // the thread handler is installed
+ if (gProcess) {
+ gProcess->mForked = true;
+ }
+ gProcessMutex.unlock();
+}
+
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
@@ -426,6 +463,7 @@
mWaitingForThreads(0),
mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
mStarvationStartTimeMs(0),
+ mForked(false),
mThreadPoolStarted(false),
mThreadPoolSeq(1),
mCallRestriction(CallRestriction::NONE) {