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

Commit 901c7455 authored by Steven Moreland's avatar Steven Moreland
Browse files

libbinder_ndk: linkToDeath/unlinkToDeath

This adds AIBinder_DeathRecipient and methods to use it in order
to receive death notifications.

Bug: 111445392
Test: ./ndk/runtests.sh
Test: manually killing a service and finding its death recipient

Change-Id: I556435cae88b01e6e2cfdc0a286bdb660859872c
parent 1b73cc2b
Loading
Loading
Loading
Loading
+97 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@

#include <android-base/logging.h>

using DeathRecipient = ::android::IBinder::DeathRecipient;

using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;
@@ -179,6 +181,63 @@ AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
    return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
}

void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
    CHECK(who == mWho);

    mOnDied(mCookie);
    mWho = nullptr;
}

AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
      : mOnDied(onDied) {
    CHECK(onDied != nullptr);
}

binder_status_t AIBinder_DeathRecipient::linkToDeath(AIBinder* binder, void* cookie) {
    CHECK(binder != nullptr);

    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);

    sp<TransferDeathRecipient> recipient =
            new TransferDeathRecipient(binder->getBinder(), cookie, mOnDied);

    binder_status_t status = binder->getBinder()->linkToDeath(recipient, cookie, 0 /*flags*/);
    if (status != EX_NONE) {
        return status;
    }

    mDeathRecipients.push_back(recipient);
    return EX_NONE;
}

binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* cookie) {
    CHECK(binder != nullptr);

    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);

    for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
        sp<TransferDeathRecipient> recipient = *it;

        if (recipient->getCookie() == cookie &&

            recipient->getWho() == binder->getBinder()) {
            mDeathRecipients.erase(it.base() - 1);

            binder_status_t status =
                    binder->getBinder()->unlinkToDeath(recipient, cookie, 0 /*flags*/);
            if (status != EX_NONE) {
                LOG(ERROR) << __func__
                           << ": removed reference to death recipient but unlink failed.";
            }
            return status;
        }
    }

    return -ENOENT;
}

// start of C-API methods

AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
    if (clazz == nullptr) {
        LOG(ERROR) << __func__ << ": Must provide class to construct local binder.";
@@ -218,6 +277,26 @@ binder_status_t AIBinder_ping(AIBinder* binder) {
    return binder->getBinder()->pingBinder();
}

binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                     void* cookie) {
    if (binder == nullptr || recipient == nullptr) {
        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
        return EX_NULL_POINTER;
    }

    return recipient->linkToDeath(binder, cookie);
}

binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                       void* cookie) {
    if (binder == nullptr || recipient == nullptr) {
        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
        return EX_NULL_POINTER;
    }

    return recipient->unlinkToDeath(binder, cookie);
}

void AIBinder_incStrong(AIBinder* binder) {
    if (binder == nullptr) {
        LOG(ERROR) << __func__ << ": on null binder";
@@ -347,3 +426,21 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa

    return parcelStatus;
}

AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
        AIBinder_DeathRecipient_onBinderDied onBinderDied) {
    if (onBinderDied == nullptr) {
        LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter.";
        return nullptr;
    }
    return new AIBinder_DeathRecipient(onBinderDied);
}

void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient** recipient) {
    if (recipient == nullptr) {
        return;
    }

    delete *recipient;
    *recipient = nullptr;
}
+37 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include "AIBinder_internal.h"

#include <atomic>
#include <mutex>
#include <vector>

#include <binder/Binder.h>
#include <binder/IBinder.h>
@@ -108,3 +110,38 @@ private:
    // one.
    const ::android::String16 mInterfaceDescriptor;
};

// Ownership is like this (when linked to death):
//
//   AIBinder_DeathRecipient -sp-> TransferDeathRecipient <-wp-> IBinder
//
// When the AIBinder_DeathRecipient is dropped, so are the actual underlying death recipients. When
// the IBinder dies, only a wp to it is kept.
struct AIBinder_DeathRecipient {
    // One of these is created for every linkToDeath. This is to be able to recover data when a
    // binderDied receipt only gives us information about the IBinder.
    struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
        TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
                               const AIBinder_DeathRecipient_onBinderDied& onDied)
              : mWho(who), mCookie(cookie), mOnDied(onDied) {}

        void binderDied(const ::android::wp<::android::IBinder>& who) override;

        const ::android::wp<::android::IBinder>& getWho() { return mWho; }
        void* getCookie() { return mCookie; }

    private:
        ::android::wp<::android::IBinder> mWho;
        void* mCookie;
        const AIBinder_DeathRecipient_onBinderDied& mOnDied;
    };

    AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
    binder_status_t linkToDeath(AIBinder* binder, void* cookie);
    binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);

private:
    std::mutex mDeathRecipientsMutex;
    std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
    AIBinder_DeathRecipient_onBinderDied mOnDied;
};
+47 −0
Original line number Diff line number Diff line
@@ -84,6 +84,10 @@ typedef struct AIBinder_Class AIBinder_Class;
 * implementation (usually a callback) to transfer all ownership to a remote process and
 * automatically be deleted when the remote process is done with it or dies. Other memory models are
 * possible, but this is the standard one.
 *
 * If the process containing an AIBinder dies, it is possible to be holding a strong reference to
 * an object which does not exist. In this case, transactions to this binder will return
 * EX_DEAD_OBJECT. See also AIBinder_linkToDeath, AIBinder_unlinkToDeath, and AIBinder_isAlive.
 */
struct AIBinder;
typedef struct AIBinder AIBinder;
@@ -96,6 +100,12 @@ typedef struct AIBinder AIBinder;
struct AIBinder_Weak;
typedef struct AIBinder_Weak AIBinder_Weak;

/**
 * Represents a handle on a death notification. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
 */
struct AIBinder_DeathRecipient;
typedef struct AIBinder_DeathRecipient AIBinder_DeathRecipient;

/**
 * This is called whenever a new AIBinder object is needed of a specific class.
 *
@@ -162,6 +172,26 @@ bool AIBinder_isAlive(const AIBinder* binder);
 */
binder_status_t AIBinder_ping(AIBinder* binder);

/**
 * Registers for notifications that the associated binder is dead. The same death recipient may be
 * associated with multiple different binders. If the binder is local, then no death recipient will
 * be given (since if the local process dies, then no recipient will exist to recieve a
 * transaction). The cookie is passed to recipient in the case that this binder dies and can be
 * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
 * This function may return a binder transaction failure. The cookie can be used both for
 * identification and holding user data.
 */
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                     void* cookie);

/**
 * Stops registration for the associated binder dying. Does not delete the recipient. This function
 * may return a binder transaction failure and in case the death recipient cannot be found, it
 * returns -ENOENT.
 */
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                       void* cookie);

/**
 * This can only be called if a strong reference to this object already exists in process.
 */
@@ -254,4 +284,21 @@ void AIBinder_Weak_delete(AIBinder_Weak** weakBinder);
 */
__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder);

/**
 * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
 */
typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie);

/**
 * Creates a new binder death recipient. This can be attached to multiple different binder objects.
 */
__attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
        AIBinder_DeathRecipient_onBinderDied onBinderDied);

/**
 * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
 * calling this as these will all be automatically unlinked.
 */
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient** recipient);

__END_DECLS
+23 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <gtest/gtest.h>
#include <iface/iface.h>

@@ -45,6 +46,28 @@ TEST(NdkBinder, RetrieveNonNdkService) {
    AIBinder_decStrong(binder);
}

void OnBinderDeath(void* cookie) {
    LOG(ERROR) << "BINDER DIED. COOKIE: " << cookie;
}

TEST(NdkBinder, LinkToDeath) {
    ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
    ABinderProcess_startThreadPool();

    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
    ASSERT_NE(nullptr, binder);

    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(OnBinderDeath);
    ASSERT_NE(nullptr, recipient);

    EXPECT_EQ(EX_NONE, AIBinder_linkToDeath(binder, recipient, nullptr));
    EXPECT_EQ(EX_NONE, AIBinder_unlinkToDeath(binder, recipient, nullptr));
    EXPECT_EQ(-ENOENT, AIBinder_unlinkToDeath(binder, recipient, nullptr));

    AIBinder_DeathRecipient_delete(&recipient);
    AIBinder_decStrong(binder);
}

class MyTestFoo : public IFoo {
    int32_t doubleNumber(int32_t in) override {
        LOG(INFO) << "doubleNumber " << in;