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

Commit f15d4292 authored by Yifan Hong's avatar Yifan Hong Committed by Automerger Merge Worker
Browse files

Merge "Add IBinder::setRpcClient" am: a0b682cc

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1683951

Change-Id: Ia2ea464b74f7b658fb8e0059ee5ede35a8bca1e7
parents 6eaa84fa a0b682cc
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -167,6 +167,10 @@ cc_library {
        binder32bit: {
            cflags: ["-DBINDER_IPC_32BIT=1"],
        },

        debuggable: {
            cflags: ["-DBINDER_RPC_DEV_SERVERS"],
        },
    },

    shared_libs: [
+116 −1
Original line number Diff line number Diff line
@@ -17,16 +17,24 @@
#include <binder/Binder.h>

#include <atomic>
#include <utils/misc.h>

#include <android-base/unique_fd.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <private/android_filesystem_config.h>
#include <utils/misc.h>

#include <inttypes.h>
#include <linux/sched.h>
#include <stdio.h>

#include "RpcState.h"

namespace android {

// Service implementations inherit from BBinder and IBinder, and this is frozen
@@ -39,6 +47,12 @@ static_assert(sizeof(IBinder) == 12);
static_assert(sizeof(BBinder) == 20);
#endif

#ifdef BINDER_RPC_DEV_SERVERS
constexpr const bool kEnableRpcDevServers = true;
#else
constexpr const bool kEnableRpcDevServers = false;
#endif

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

IBinder::IBinder()
@@ -136,6 +150,33 @@ status_t IBinder::getDebugPid(pid_t* out) {
    return OK;
}

status_t IBinder::setRpcClientDebug(android::base::unique_fd socketFd, uint32_t maxRpcThreads) {
    if constexpr (!kEnableRpcDevServers) {
        ALOGW("setRpcClientDebug disallowed because RPC is not enabled");
        return INVALID_OPERATION;
    }

    BBinder* local = this->localBinder();
    if (local != nullptr) {
        return local->BBinder::setRpcClientDebug(std::move(socketFd), maxRpcThreads);
    }

    BpBinder* proxy = this->remoteBinder();
    LOG_ALWAYS_FATAL_IF(proxy == nullptr, "binder object must be either local or remote");

    Parcel data;
    Parcel reply;
    status_t status;
    if (status = data.writeBool(socketFd.ok()); status != OK) return status;
    if (socketFd.ok()) {
        // writeUniqueFileDescriptor currently makes an unnecessary dup().
        status = data.writeFileDescriptor(socketFd.release(), true /* own */);
        if (status != OK) return status;
    }
    if (status = data.writeUint32(maxRpcThreads); status != OK) return status;
    return transact(SET_RPC_CLIENT_TRANSACTION, data, &reply);
}

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

class BBinder::Extras
@@ -150,6 +191,7 @@ public:

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

@@ -199,6 +241,10 @@ status_t BBinder::transact(
        case DEBUG_PID_TRANSACTION:
            err = reply->writeInt32(getDebugPid());
            break;
        case SET_RPC_CLIENT_TRANSACTION: {
            err = setRpcClientDebug(data);
            break;
        }
        default:
            err = onTransact(code, data, reply, flags);
            break;
@@ -368,6 +414,75 @@ void BBinder::setExtension(const sp<IBinder>& extension) {
    e->mExtension = extension;
}

status_t BBinder::setRpcClientDebug(const Parcel& data) {
    if constexpr (!kEnableRpcDevServers) {
        ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
        return INVALID_OPERATION;
    }
    uid_t uid = IPCThreadState::self()->getCallingUid();
    if (uid != AID_ROOT) {
        ALOGE("%s: not allowed because client %" PRIu32 " is not root", __PRETTY_FUNCTION__, uid);
        return PERMISSION_DENIED;
    }
    status_t status;
    bool hasSocketFd;
    android::base::unique_fd clientFd;
    uint32_t maxRpcThreads;

    if (status = data.readBool(&hasSocketFd); status != OK) return status;
    if (hasSocketFd) {
        if (status = data.readUniqueFileDescriptor(&clientFd); status != OK) return status;
    }
    if (status = data.readUint32(&maxRpcThreads); status != OK) return status;

    return setRpcClientDebug(std::move(clientFd), maxRpcThreads);
}

status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd, uint32_t maxRpcThreads) {
    if constexpr (!kEnableRpcDevServers) {
        ALOGW("%s: disallowed because RPC is not enabled", __PRETTY_FUNCTION__);
        return INVALID_OPERATION;
    }

    const int socketFdForPrint = socketFd.get();
    LOG_RPC_DETAIL("%s(%d, %" PRIu32 ")", __PRETTY_FUNCTION__, socketFdForPrint, maxRpcThreads);

    if (!socketFd.ok()) {
        ALOGE("%s: No socket FD provided.", __PRETTY_FUNCTION__);
        return BAD_VALUE;
    }
    if (maxRpcThreads <= 0) {
        ALOGE("%s: RPC is useless with %" PRIu32 " threads.", __PRETTY_FUNCTION__, maxRpcThreads);
        return BAD_VALUE;
    }

    // TODO(b/182914638): RPC and binder should share the same thread pool count.
    size_t binderThreadPoolMaxCount = ProcessState::self()->getThreadPoolMaxThreadCount();
    if (binderThreadPoolMaxCount <= 1) {
        ALOGE("%s: ProcessState thread pool max count is %zu. RPC is disabled for this service "
              "because RPC requires the service to support multithreading.",
              __PRETTY_FUNCTION__, binderThreadPoolMaxCount);
        return INVALID_OPERATION;
    }

    Extras* e = getOrCreateExtras();
    AutoMutex _l(e->mLock);
    if (e->mRpcServer != nullptr) {
        ALOGE("%s: Already have RPC client", __PRETTY_FUNCTION__);
        return ALREADY_EXISTS;
    }
    e->mRpcServer = RpcServer::make();
    LOG_ALWAYS_FATAL_IF(e->mRpcServer == nullptr, "RpcServer::make returns null");
    e->mRpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
    // Weak ref to avoid circular dependency: BBinder -> RpcServer -X-> BBinder
    e->mRpcServer->setRootObjectWeak(wp<BBinder>::fromExisting(this));
    e->mRpcServer->setupExternalServer(std::move(socketFd));
    e->mRpcServer->start();
    LOG_RPC_DETAIL("%s(%d, %" PRIu32 ") successful", __PRETTY_FUNCTION__, socketFdForPrint,
                   maxRpcThreads);
    return OK;
}

BBinder::~BBinder()
{
    Extras* e = mExtras.load(std::memory_order_relaxed);
+8 −0
Original line number Diff line number Diff line
@@ -359,6 +359,14 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
    return result;
}

size_t ProcessState::getThreadPoolMaxThreadCount() const {
    // may actually be one more than this, if join is called
    if (mThreadPoolStarted) return mMaxThreads;
    // must not be initialized or maybe has poll thread setup, we
    // currently don't track this in libbinder
    return 0;
}

status_t ProcessState::enableOnewaySpamDetection(bool enable) {
    uint32_t enableDetection = enable ? 1 : 0;
    if (ioctl(mDriverFD, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enableDetection) == -1) {
+5 −0
Original line number Diff line number Diff line
@@ -94,6 +94,9 @@ public:

    pid_t               getDebugPid();

    [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd,
                                             uint32_t maxRpcThreads);

protected:
    virtual             ~BBinder();

@@ -111,6 +114,8 @@ private:

    Extras*             getOrCreateExtras();

    [[nodiscard]] status_t setRpcClientDebug(const Parcel& data);

    std::atomic<Extras*> mExtras;

    friend ::android::internal::Stability;
+22 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ public:
        SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
        EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'),
        DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'),
        SET_RPC_CLIENT_TRANSACTION = B_PACK_CHARS('_', 'R', 'P', 'C'),

        // See android.os.IBinder.TWEET_TRANSACTION
        // Most importantly, messages can be anything not exceeding 130 UTF-8
@@ -152,6 +153,27 @@ public:
     */
    status_t                getDebugPid(pid_t* outPid);

    /**
     * Set the RPC client fd to this binder service, for debugging. This is only available on
     * debuggable builds.
     *
     * |maxRpcThreads| must be positive because RPC is useless without threads.
     *
     * When this is called on a binder service, the service:
     * 1. sets up RPC server
     * 2. spawns 1 new thread that calls RpcServer::join()
     *    - join() spawns at most |maxRpcThreads| threads that accept() connections; see RpcServer
     *
     * setRpcClientDebug() may only be called once.
     * TODO(b/182914638): If allow to shut down the client, addRpcClient can be called repeatedly.
     *
     * 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
     * functions with multithreading support.
     */
    [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd socketFd,
                                             uint32_t maxRpcThreads);

    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t        transact(   uint32_t code,
                                        const Parcel& data,
Loading