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

Commit 76d2c1f0 authored by Steven Moreland's avatar Steven Moreland
Browse files

libbinder: RPC fixup retry logic

By always reading from the pipe in the test, we can ensure we only try
to connect to a server once it's started. After this, additional retry
logic is unneeded.

Bug: 185167543
Test: binderRpcTest
Test: binderRpcTest (after introducing 100ms sleep before 'accept4' in
    RpcServer to simulate a server that is busy doing something else or
    busy accepting other calls from other clients)
Change-Id: I9b5b2876aa74e6ef1b6e8edc4c25124c29446b86
parent bd5002b5
Loading
Loading
Loading
Loading
+36 −26
Original line number Diff line number Diff line
@@ -215,28 +215,34 @@ bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {

    // we've already setup one client
    for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
        // TODO(b/185167543): avoid race w/ accept4 not being called on server
        for (size_t tries = 0; tries < 5; tries++) {
            if (setupOneSocketClient(addr, mId.value())) break;
            usleep(10000);
        }
        // TODO(b/185167543): shutdown existing connections?
        if (!setupOneSocketClient(addr, mId.value())) return false;
    }

    return true;
}

bool RpcSession::setupOneSocketClient(const RpcSocketAddress& addr, int32_t id) {
    for (size_t tries = 0; tries < 5; tries++) {
        if (tries > 0) usleep(10000);

        unique_fd serverFd(
                TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
        if (serverFd == -1) {
            int savedErrno = errno;
        ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
            ALOGE("Could not create socket at %s: %s", addr.toString().c_str(),
                  strerror(savedErrno));
            return false;
        }

        if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
            if (errno == ECONNRESET) {
                ALOGW("Connection reset on %s", addr.toString().c_str());
                continue;
            }
            int savedErrno = errno;
        ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
            ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
                  strerror(savedErrno));
            return false;
        }

@@ -253,6 +259,10 @@ bool RpcSession::setupOneSocketClient(const RpcSocketAddress& addr, int32_t id)
        return true;
    }

    ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
    return false;
}

void RpcSession::addClient(unique_fd fd) {
    std::lock_guard<std::mutex> _l(mMutex);
    sp<RpcConnection> session = sp<RpcConnection>::make();
+20 −22
Original line number Diff line number Diff line
@@ -327,6 +327,8 @@ public:
                    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
                    server->setMaxThreads(numThreads);

                    unsigned int outPort = 0;

                    switch (socketType) {
                        case SocketType::UNIX:
                            CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
@@ -335,34 +337,31 @@ public:
                            CHECK(server->setupVsockServer(vsockPort));
                            break;
                        case SocketType::INET: {
                            unsigned int outPort = 0;
                            CHECK(server->setupInetServer(0, &outPort));
                            CHECK_NE(0, outPort);
                            CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort,
                                                            sizeof(outPort)));
                            break;
                        }
                        default:
                            LOG_ALWAYS_FATAL("Unknown socket type");
                    }

                    CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort, sizeof(outPort)));

                    configure(server);

                    server->join();
                }),
        };

        unsigned int inetPort = 0;
        // always read socket, so that we have waited for the server to start
        unsigned int outPort = 0;
        CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &outPort, sizeof(outPort)));
        if (socketType == SocketType::INET) {
            CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &inetPort,
                                           sizeof(inetPort)));
            CHECK_NE(0, inetPort);
            CHECK_NE(0, outPort);
        }

        for (size_t i = 0; i < numSessions; i++) {
            sp<RpcSession> session = RpcSession::make();
            for (size_t tries = 0; tries < 10; tries++) {
                usleep(10000);
            switch (socketType) {
                case SocketType::UNIX:
                    if (session->setupUnixDomainClient(addr.c_str())) goto success;
@@ -371,12 +370,11 @@ public:
                    if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
                    break;
                case SocketType::INET:
                        if (session->setupInetClient("127.0.0.1", inetPort)) goto success;
                    if (session->setupInetClient("127.0.0.1", outPort)) goto success;
                    break;
                default:
                    LOG_ALWAYS_FATAL("Unknown socket type");
            }
            }
            LOG_ALWAYS_FATAL("Could not connect");
        success:
            ret.sessions.push_back({session, session->getRootObject()});