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

Commit 8b890853 authored by Yifan Hong's avatar Yifan Hong
Browse files

Implement keepAliveBinder for setRpcClientDebug

setRpcClientDebug can now be called multiple times. Each will
set up a different RpcServer and opens up a different port.

When keepAliveBinder dies, the corresponding RpcServer also
dies.

Also fixes tests to meet new expectations.
- Positive tests now only run on remote binder, because the
  keepAliveBinder object cannot be a local binder to call
  linkToDeath.
- Negative tests keeps running on local and remote binders.
- Use real servicedispatcher.

Test: binderLibTest
Test: manual with servicedispatcher.

Bug: 182914638

Change-Id: Ic46ac54bb7988ee7d65546563f56f0a02c29ce7c
parent 02530ec0
Loading
Loading
Loading
Loading
+59 −12
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#include <binder/Binder.h>
#include <binder/Binder.h>


#include <atomic>
#include <atomic>
#include <set>


#include <android-base/unique_fd.h>
#include <android-base/unique_fd.h>
#include <binder/BpBinder.h>
#include <binder/BpBinder.h>
@@ -180,6 +181,38 @@ status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd,


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------


class BBinder::RpcServerLink : public IBinder::DeathRecipient {
public:
    // On binder died, calls RpcServer::shutdown on @a rpcServer, and removes itself from @a binder.
    RpcServerLink(const sp<RpcServer>& rpcServer, const sp<IBinder>& keepAliveBinder,
                  const wp<BBinder>& binder)
          : mRpcServer(rpcServer), mKeepAliveBinder(keepAliveBinder), mBinder(binder) {}
    void binderDied(const wp<IBinder>&) override {
        LOG_RPC_DETAIL("RpcServerLink: binder died, shutting down RpcServer");
        if (mRpcServer == nullptr) {
            ALOGW("RpcServerLink: Unable to shut down RpcServer because it does not exist.");
        } else {
            ALOGW_IF(!mRpcServer->shutdown(),
                     "RpcServerLink: RpcServer did not shut down properly. Not started?");
        }
        mRpcServer.clear();

        auto promoted = mBinder.promote();
        if (promoted == nullptr) {
            ALOGW("RpcServerLink: Unable to remove link from parent binder object because parent "
                  "binder object is gone.");
        } else {
            promoted->removeRpcServerLink(sp<RpcServerLink>::fromExisting(this));
        }
        mBinder.clear();
    }

private:
    sp<RpcServer> mRpcServer;
    sp<IBinder> mKeepAliveBinder; // hold to avoid automatically unlinking
    wp<BBinder> mBinder;
};

class BBinder::Extras
class BBinder::Extras
{
{
public:
public:
@@ -192,7 +225,7 @@ public:


    // for below objects
    // for below objects
    Mutex mLock;
    Mutex mLock;
    sp<RpcServer> mRpcServer;
    std::set<sp<RpcServerLink>> mRpcServerLinks;
    BpBinder::ObjectManager mObjects;
    BpBinder::ObjectManager mObjects;
};
};


@@ -489,24 +522,38 @@ status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd,
        return INVALID_OPERATION;
        return INVALID_OPERATION;
    }
    }


    // Weak ref to avoid circular dependency:
    // BBinder -> RpcServerLink ----> RpcServer -X-> BBinder
    //                          `-X-> BBinder
    auto weakThis = wp<BBinder>::fromExisting(this);

    Extras* e = getOrCreateExtras();
    Extras* e = getOrCreateExtras();
    AutoMutex _l(e->mLock);
    AutoMutex _l(e->mLock);
    if (e->mRpcServer != nullptr) {
    auto rpcServer = RpcServer::make();
        ALOGE("%s: Already have RPC client", __PRETTY_FUNCTION__);
    LOG_ALWAYS_FATAL_IF(rpcServer == nullptr, "RpcServer::make returns null");
        return ALREADY_EXISTS;
    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
    }
    auto link = sp<RpcServerLink>::make(rpcServer, keepAliveBinder, weakThis);
    e->mRpcServer = RpcServer::make();
    if (auto status = keepAliveBinder->linkToDeath(link, nullptr, 0); status != OK) {
    LOG_ALWAYS_FATAL_IF(e->mRpcServer == nullptr, "RpcServer::make returns null");
        ALOGE("%s: keepAliveBinder->linkToDeath returns %s", __PRETTY_FUNCTION__,
    e->mRpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
              statusToString(status).c_str());
    // Weak ref to avoid circular dependency: BBinder -> RpcServer -X-> BBinder
        return status;
    e->mRpcServer->setRootObjectWeak(wp<BBinder>::fromExisting(this));
    }
    e->mRpcServer->setupExternalServer(std::move(socketFd));
    rpcServer->setRootObjectWeak(weakThis);
    e->mRpcServer->setMaxThreads(binderThreadPoolMaxCount);
    rpcServer->setupExternalServer(std::move(socketFd));
    e->mRpcServer->start();
    rpcServer->setMaxThreads(binderThreadPoolMaxCount);
    rpcServer->start();
    e->mRpcServerLinks.emplace(link);
    LOG_RPC_DETAIL("%s(fd=%d) successful", __PRETTY_FUNCTION__, socketFdForPrint);
    LOG_RPC_DETAIL("%s(fd=%d) successful", __PRETTY_FUNCTION__, socketFdForPrint);
    return OK;
    return OK;
}
}


void BBinder::removeRpcServerLink(const sp<RpcServerLink>& link) {
    Extras* e = mExtras.load(std::memory_order_acquire);
    if (!e) return;
    AutoMutex _l(e->mLock);
    (void)e->mRpcServerLinks.erase(link);
}

BBinder::~BBinder()
BBinder::~BBinder()
{
{
    Extras* e = mExtras.load(std::memory_order_relaxed);
    Extras* e = mExtras.load(std::memory_order_relaxed);
+2 −0
Original line number Original line Diff line number Diff line
@@ -117,11 +117,13 @@ private:
                        BBinder(const BBinder& o);
                        BBinder(const BBinder& o);
            BBinder&    operator=(const BBinder& o);
            BBinder&    operator=(const BBinder& o);


    class RpcServerLink;
    class Extras;
    class Extras;


    Extras*             getOrCreateExtras();
    Extras*             getOrCreateExtras();


    [[nodiscard]] status_t setRpcClientDebug(const Parcel& data);
    [[nodiscard]] status_t setRpcClientDebug(const Parcel& data);
    void removeRpcServerLink(const sp<RpcServerLink>& link);


    std::atomic<Extras*> mExtras;
    std::atomic<Extras*> mExtras;


+2 −2
Original line number Original line Diff line number Diff line
@@ -162,8 +162,8 @@ public:
     * 2. spawns 1 new thread that calls RpcServer::join()
     * 2. spawns 1 new thread that calls RpcServer::join()
     *    - join() spawns some number of threads that accept() connections; see RpcServer
     *    - join() spawns some number of threads that accept() connections; see RpcServer
     *
     *
     * setRpcClientDebug() may only be called once.
     * setRpcClientDebug() may be called multiple times. Each call will add a new RpcServer
     * TODO(b/182914638): If allow to shut down the client, addRpcClient can be called repeatedly.
     * and opens up a TCP port.
     *
     *
     * Note: A thread is spawned for each accept()'ed fd, which may call into functions of the
     * Note: A thread is spawned for each accept()'ed fd, which may call into functions of the
     * interface freely. See RpcServer::join(). To avoid such race conditions, implement the service
     * interface freely. See RpcServer::join(). To avoid such race conditions, implement the service
+2 −0
Original line number Original line Diff line number Diff line
@@ -62,6 +62,7 @@ cc_test {
    shared_libs: [
    shared_libs: [
        "libbase",
        "libbase",
        "libbinder",
        "libbinder",
        "liblog",
        "libutils",
        "libutils",
    ],
    ],
    static_libs: [
    static_libs: [
@@ -104,6 +105,7 @@ cc_test {
    shared_libs: [
    shared_libs: [
        "libbase",
        "libbase",
        "libbinder",
        "libbinder",
        "liblog",
        "libutils",
        "libutils",
    ],
    ],
    static_libs: [
    static_libs: [
+36 −32
Original line number Original line Diff line number Diff line
@@ -15,14 +15,13 @@
 */
 */


#include <errno.h>
#include <errno.h>
#include <fcntl.h>
#include <fstream>
#include <poll.h>
#include <poll.h>
#include <pthread.h>
#include <pthread.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>


#include <chrono>
#include <chrono>
#include <fstream>
#include <thread>
#include <thread>


#include <gmock/gmock.h>
#include <gmock/gmock.h>
@@ -31,6 +30,7 @@
#include <android-base/properties.h>
#include <android-base/properties.h>
#include <android-base/result-gmock.h>
#include <android-base/result-gmock.h>
#include <android-base/result.h>
#include <android-base/result.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android-base/unique_fd.h>
#include <binder/Binder.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
#include <binder/BpBinder.h>
@@ -55,6 +55,7 @@ using namespace android;
using namespace std::string_literals;
using namespace std::string_literals;
using namespace std::chrono_literals;
using namespace std::chrono_literals;
using android::base::testing::HasValue;
using android::base::testing::HasValue;
using android::base::testing::Ok;
using testing::ExplainMatchResult;
using testing::ExplainMatchResult;
using testing::Not;
using testing::Not;
using testing::WithParamInterface;
using testing::WithParamInterface;
@@ -1200,7 +1201,35 @@ public:
    }
    }
};
};


class BinderLibRpcTest : public BinderLibRpcTestBase, public WithParamInterface<bool> {
class BinderLibRpcTest : public BinderLibRpcTestBase {};

TEST_F(BinderLibRpcTest, SetRpcClientDebug) {
    auto binder = addServer();
    ASSERT_TRUE(binder != nullptr);
    auto [socket, port] = CreateSocket();
    ASSERT_TRUE(socket.ok());
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), sp<BBinder>::make()), StatusEq(OK));
}

// Tests for multiple RpcServer's on the same binder object.
TEST_F(BinderLibRpcTest, SetRpcClientDebugTwice) {
    auto binder = addServer();
    ASSERT_TRUE(binder != nullptr);

    auto [socket1, port1] = CreateSocket();
    ASSERT_TRUE(socket1.ok());
    auto keepAliveBinder1 = sp<BBinder>::make();
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket1), keepAliveBinder1), StatusEq(OK));

    auto [socket2, port2] = CreateSocket();
    ASSERT_TRUE(socket2.ok());
    auto keepAliveBinder2 = sp<BBinder>::make();
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket2), keepAliveBinder2), StatusEq(OK));
}

// Negative tests for RPC APIs on IBinder. Call should fail in the same way on both remote and
// local binders.
class BinderLibRpcTestP : public BinderLibRpcTestBase, public WithParamInterface<bool> {
public:
public:
    sp<IBinder> GetService() {
    sp<IBinder> GetService() {
        return GetParam() ? sp<IBinder>(addServer()) : sp<IBinder>(sp<BBinder>::make());
        return GetParam() ? sp<IBinder>(addServer()) : sp<IBinder>(sp<BBinder>::make());
@@ -1210,47 +1239,22 @@ public:
    }
    }
};
};


TEST_P(BinderLibRpcTest, SetRpcClientDebug) {
TEST_P(BinderLibRpcTestP, SetRpcClientDebugNoFd) {
    auto binder = GetService();
    ASSERT_TRUE(binder != nullptr);
    auto [socket, port] = CreateSocket();
    ASSERT_TRUE(socket.ok());
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), sp<BBinder>::make()), StatusEq(OK));
}

TEST_P(BinderLibRpcTest, SetRpcClientDebugNoFd) {
    auto binder = GetService();
    auto binder = GetService();
    ASSERT_TRUE(binder != nullptr);
    ASSERT_TRUE(binder != nullptr);
    EXPECT_THAT(binder->setRpcClientDebug(android::base::unique_fd(), sp<BBinder>::make()),
    EXPECT_THAT(binder->setRpcClientDebug(android::base::unique_fd(), sp<BBinder>::make()),
                StatusEq(BAD_VALUE));
                StatusEq(BAD_VALUE));
}
}


TEST_P(BinderLibRpcTest, SetRpcClientDebugNoKeepAliveBinder) {
TEST_P(BinderLibRpcTestP, SetRpcClientDebugNoKeepAliveBinder) {
    auto binder = GetService();
    auto binder = GetService();
    ASSERT_TRUE(binder != nullptr);
    ASSERT_TRUE(binder != nullptr);
    auto [socket, port] = CreateSocket();
    auto [socket, port] = CreateSocket();
    ASSERT_TRUE(socket.ok());
    ASSERT_TRUE(socket.ok());
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), nullptr), StatusEq(UNEXPECTED_NULL));
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket), nullptr), StatusEq(UNEXPECTED_NULL));
}
}

INSTANTIATE_TEST_CASE_P(BinderLibTest, BinderLibRpcTestP, testing::Bool(),
TEST_P(BinderLibRpcTest, SetRpcClientDebugTwice) {
                        BinderLibRpcTestP::ParamToString);
    auto binder = GetService();
    ASSERT_TRUE(binder != nullptr);

    auto [socket1, port1] = CreateSocket();
    ASSERT_TRUE(socket1.ok());
    auto keepAliveBinder1 = sp<BBinder>::make();
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket1), keepAliveBinder1), StatusEq(OK));

    auto [socket2, port2] = CreateSocket();
    ASSERT_TRUE(socket2.ok());
    auto keepAliveBinder2 = sp<BBinder>::make();
    EXPECT_THAT(binder->setRpcClientDebug(std::move(socket2), keepAliveBinder2),
                StatusEq(ALREADY_EXISTS));
}

INSTANTIATE_TEST_CASE_P(BinderLibTest, BinderLibRpcTest, testing::Bool(),
                        BinderLibRpcTest::ParamToString);


class BinderLibTestService;
class BinderLibTestService;
class BinderLibRpcClientTest : public BinderLibRpcTestBase,
class BinderLibRpcClientTest : public BinderLibRpcTestBase,