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

Commit 2b07dff6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "ndk: Add way to manage ownership of linkToDeath cookie" am: f76f98d7

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

Change-Id: Ieae1c42e0cbe2256861503f3a36d3923b0f52c87
parents 06b1d107 f76f98d7
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -373,6 +373,12 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) {
    return clazz->getInterfaceDescriptorUtf8();
}

AIBinder_DeathRecipient::TransferDeathRecipient::~TransferDeathRecipient() {
    if (mOnUnlinked != nullptr) {
        mOnUnlinked(mCookie);
    }
}

void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
    CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get()
                       << " (" << mWho.get_refs() << ")";
@@ -394,7 +400,7 @@ void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinde
}

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

@@ -412,10 +418,12 @@ binder_status_t AIBinder_DeathRecipient::linkToDeath(const sp<IBinder>& binder,
    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);

    sp<TransferDeathRecipient> recipient =
            new TransferDeathRecipient(binder, cookie, this, mOnDied);
            new TransferDeathRecipient(binder, cookie, this, mOnDied, mOnUnlinked);

    status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/);
    if (status != STATUS_OK) {
        // When we failed to link, the destructor of TransferDeathRecipient runs here, which
        // ensures that mOnUnlinked is called before we return with an error from this method.
        return PruneStatusT(status);
    }

@@ -448,6 +456,10 @@ binder_status_t AIBinder_DeathRecipient::unlinkToDeath(const sp<IBinder>& binder
    return STATUS_NAME_NOT_FOUND;
}

void AIBinder_DeathRecipient::setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) {
    mOnUnlinked = onUnlinked;
}

// start of C-API methods

AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
@@ -689,6 +701,15 @@ AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
    return ret;
}

void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient,
                                           AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) {
    if (recipient == nullptr) {
        return;
    }

    recipient->setOnUnlinked(onUnlinked);
}

void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) {
    if (recipient == nullptr) {
        return;
+11 −2
Original line number Diff line number Diff line
@@ -148,8 +148,14 @@ struct AIBinder_DeathRecipient : ::android::RefBase {
    struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
        TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
                               const ::android::wp<AIBinder_DeathRecipient>& parentRecipient,
                               const AIBinder_DeathRecipient_onBinderDied onDied)
            : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {}
                               const AIBinder_DeathRecipient_onBinderDied onDied,
                               const AIBinder_DeathRecipient_onBinderUnlinked onUnlinked)
            : mWho(who),
              mCookie(cookie),
              mParentRecipient(parentRecipient),
              mOnDied(onDied),
              mOnUnlinked(onUnlinked) {}
        ~TransferDeathRecipient();

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

@@ -165,11 +171,13 @@ struct AIBinder_DeathRecipient : ::android::RefBase {
        // This is kept separately from AIBinder_DeathRecipient in case the death recipient is
        // deleted while the death notification is fired
        const AIBinder_DeathRecipient_onBinderDied mOnDied;
        const AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked;
    };

    explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
    binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie);
    binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie);
    void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked);

   private:
    // When the user of this API deletes a Bp object but not the death recipient, the
@@ -180,4 +188,5 @@ struct AIBinder_DeathRecipient : ::android::RefBase {
    std::mutex mDeathRecipientsMutex;
    std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
    AIBinder_DeathRecipient_onBinderDied mOnDied;
    AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked;
};
+60 −2
Original line number Diff line number Diff line
@@ -319,9 +319,9 @@ binder_status_t AIBinder_dump(AIBinder* binder, int fd, const char** args, uint3
/**
 * 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
 * be given (since if the local process dies, then no recipient will exist to receive 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).
 * null. The exact cookie must also be used to unlink this transaction (see AIBinder_unlinkToDeath).
 * This function may return a binder transaction failure. The cookie can be used both for
 * identification and holding user data.
 *
@@ -348,6 +348,10 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient*
 * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
 * automatically unlinked.
 *
 * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you
 * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using
 * AIBinder_DeathRecipient_setOnUnlinked.
 *
 * Available since API level 29.
 *
 * \param binder the binder object to remove a previously linked death recipient from.
@@ -567,6 +571,22 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Wea
 */
typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);

/**
 * This function is intended for cleaning up the data in the provided cookie, and it is executed
 * when the DeathRecipient is unlinked. When the DeathRecipient is unlinked due to a death receipt,
 * this method is called after the call to onBinderDied.
 *
 * This method is called once for each binder that is unlinked. Hence, if the same cookie is passed
 * to multiple binders, then the caller is responsible for reference counting the cookie.
 *
 * See also AIBinder_linkToDeath/AIBinder_unlinkToDeath.
 *
 * Available since API level 33.
 *
 * \param cookie the cookie passed to AIBinder_linkToDeath.
 */
typedef void (*AIBinder_DeathRecipient_onBinderUnlinked)(void* cookie) __INTRODUCED_IN(33);

/**
 * Creates a new binder death recipient. This can be attached to multiple different binder objects.
 *
@@ -579,10 +599,48 @@ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_
__attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
        AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);

/**
 * Set the callback to be called when this DeathRecipient is unlinked from a binder. The callback is
 * called in the following situations:
 *
 *  1. If the binder died, shortly after the call to onBinderDied.
 *  2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or
 *     AIBinder_DeathRecipient_delete.
 *  3. During or shortly after the AIBinder_linkToDeath call if it returns an error.
 *
 * It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the
 * process is aborted before the binder is unlinked.
 *
 * Be aware that when the binder is explicitly unlinked, it is not guaranteed that onUnlinked has
 * been called before the call to AIBinder_unlinkToDeath or AIBinder_DeathRecipient_delete returns.
 * For example, if the binder dies concurrently with a call to AIBinder_unlinkToDeath, the binder is
 * not unlinked until after the death notification is delivered, even if AIBinder_unlinkToDeath
 * returns before that happens.
 *
 * This method should be called before linking the DeathRecipient to a binder because the function
 * pointer is cached. If you change it after linking to a binder, it is unspecified whether the old
 * binder will call the old or new onUnlinked callback.
 *
 * The onUnlinked argument may be null. In this case, no notification is given when the binder is
 * unlinked.
 *
 * Available since API level 33.
 *
 * \param recipient the DeathRecipient to set the onUnlinked callback for.
 * \param onUnlinked the callback to call when a binder is unlinked from recipient.
 */
void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient,
                                           AIBinder_DeathRecipient_onBinderUnlinked onUnlinked)
        __INTRODUCED_IN(33);

/**
 * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
 * calling this as these will all be automatically unlinked.
 *
 * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you
 * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using
 * AIBinder_DeathRecipient_setOnUnlinked.
 *
 * Available since API level 29.
 *
 * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
+1 −0
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ LIBBINDER_NDK31 { # introduced=31
LIBBINDER_NDK33 { # introduced=33
  global:
    AIBinder_Class_disableInterfaceTokenHeader;
    AIBinder_DeathRecipient_setOnUnlinked;
    AParcel_marshal;
    AParcel_unmarshal;
};
+35 −8
Original line number Diff line number Diff line
@@ -395,9 +395,16 @@ TEST(NdkBinder, ActiveServicesCallbackTest) {
            << "Service failed to shut down.";
}

struct DeathRecipientCookie {
    std::function<void(void)>*onDeath, *onUnlink;
};
void LambdaOnDeath(void* cookie) {
    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
    (*onDeath)();
    auto funcs = static_cast<DeathRecipientCookie*>(cookie);
    (*funcs->onDeath)();
};
void LambdaOnUnlink(void* cookie) {
    auto funcs = static_cast<DeathRecipientCookie*>(cookie);
    (*funcs->onUnlink)();
};
TEST(NdkBinder, DeathRecipient) {
    using namespace std::chrono_literals;
@@ -409,26 +416,46 @@ TEST(NdkBinder, DeathRecipient) {

    std::mutex deathMutex;
    std::condition_variable deathCv;
    bool deathRecieved = false;
    bool deathReceived = false;

    std::function<void(void)> onDeath = [&] {
        std::cerr << "Binder died (as requested)." << std::endl;
        deathRecieved = true;
        deathReceived = true;
        deathCv.notify_one();
    };

    std::mutex unlinkMutex;
    std::condition_variable unlinkCv;
    bool unlinkReceived = false;
    bool wasDeathReceivedFirst = false;

    std::function<void(void)> onUnlink = [&] {
        std::cerr << "Binder unlinked (as requested)." << std::endl;
        wasDeathReceivedFirst = deathReceived;
        unlinkReceived = true;
        unlinkCv.notify_one();
    };

    DeathRecipientCookie cookie = {&onDeath, &onUnlink};

    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
    AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink);

    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&cookie)));

    // the binder driver should return this if the service dies during the transaction
    EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());

    foo = nullptr;

    std::unique_lock<std::mutex> lock(deathMutex);
    EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
    EXPECT_TRUE(deathRecieved);
    std::unique_lock<std::mutex> lockDeath(deathMutex);
    EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; }));
    EXPECT_TRUE(deathReceived);

    std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
    EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; }));
    EXPECT_TRUE(unlinkReceived);
    EXPECT_TRUE(wasDeathReceivedFirst);

    AIBinder_DeathRecipient_delete(recipient);
    AIBinder_decStrong(binder);
Loading