Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee9df901 authored by Steven Moreland's avatar Steven Moreland
Browse files

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
parent d8b3d5f0
Loading
Loading
Loading
Loading
+40 −2
Original line number Diff line number Diff line
@@ -89,13 +89,23 @@ sp<ProcessState> ProcessState::selfOrNull()
    return init(nullptr, false /*requireDefault*/);
}

sp<ProcessState> ProcessState::init(const char *driver, bool 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)
{

    if (driver == nullptr) {
        std::lock_guard<std::mutex> l(gProcessMutex);
        if (gProcess) {
            verifyNotForked(gProcess->mForked);
        }
        return gProcess;
    }

@@ -106,6 +116,14 @@ sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
            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 @@ sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
                            gProcess->getDriverName().c_str(), driver);
    }

    verifyNotForked(gProcess->mForked);
    return gProcess;
}

@@ -137,6 +156,24 @@ sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
    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 @@ ProcessState::ProcessState(const char* driver)
        mWaitingForThreads(0),
        mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
        mStarvationStartTimeMs(0),
        mForked(false),
        mThreadPoolStarted(false),
        mThreadPoolSeq(1),
        mCallRestriction(CallRestriction::NONE) {
+5 −0
Original line number Diff line number Diff line
@@ -94,6 +94,10 @@ public:
private:
    static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);

    static void onFork();
    static void parentPostFork();
    static void childPostFork();

    friend class IPCThreadState;
    friend class sp<ProcessState>;

@@ -132,6 +136,7 @@ private:

    Vector<handle_entry> mHandleToObject;

    bool mForked;
    bool mThreadPoolStarted;
    volatile int32_t mThreadPoolSeq;