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

Commit 5d62e445 authored by Steven Moreland's avatar Steven Moreland
Browse files

libbinder_ndk: distinguish exception/status_t

Previously here, I had erroneously used EX_* values instead of using
values corresponding to status_t.

This CL defines the set of errors that can be returned from APIs and
constrains the return set to be exactly and only those values.

Exception values are currently not used, but they will be used for
a Status-like object since they are required for communicating with
the SDK (Java). This is also why they were not removed.

Bug: 111445392
Test: ./ndk/runtests.sh
Change-Id: I24bbebae60c167d7e050ee608c24cc1ffc8a9101
parent 34da9eec
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ cc_library {
        "ibinder.cpp",
        "parcel.cpp",
        "process.cpp",
        "status.cpp",
        "service_manager.cpp",
    ],

+38 −33
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <android/binder_status.h>
#include "parcel_internal.h"
#include "status_internal.h"

#include <android-base/logging.h>

@@ -27,6 +28,7 @@ using DeathRecipient = ::android::IBinder::DeathRecipient;
using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;
using ::android::status_t;
using ::android::String16;
using ::android::wp;

@@ -116,17 +118,18 @@ const String16& ABBinder::getInterfaceDescriptor() const {
    return getClass()->getInterfaceDescriptor();
}

binder_status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
                              binder_flags_t flags) {
    if (isUserCommand(code)) {
        if (!data.checkInterface(this)) {
            return EX_ILLEGAL_STATE;
            return STATUS_PERMISSION_DENIED;
        }

        const AParcel in = AParcel::readOnly(this, &data);
        AParcel out = AParcel(this, reply, false /*owns*/);

        return getClass()->onTransact(this, code, &in, &out);
        binder_status_t status = getClass()->onTransact(this, code, &in, &out);
        return PruneStatusT(status);
    } else {
        return BBinder::onTransact(code, data, reply, flags);
    }
@@ -253,13 +256,13 @@ binder_status_t AIBinder_DeathRecipient::linkToDeath(AIBinder* binder, void* coo
    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;
    status_t status = binder->getBinder()->linkToDeath(recipient, cookie, 0 /*flags*/);
    if (status != STATUS_OK) {
        return PruneStatusT(status);
    }

    mDeathRecipients.push_back(recipient);
    return EX_NONE;
    return STATUS_OK;
}

binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* cookie) {
@@ -270,22 +273,19 @@ binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* c
    for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
        sp<TransferDeathRecipient> recipient = *it;

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

            recipient->getWho() == binder->getBinder()) {
        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) {
            status_t status = binder->getBinder()->unlinkToDeath(recipient, cookie, 0 /*flags*/);
            if (status != ::android::OK) {
                LOG(ERROR) << __func__
                           << ": removed reference to death recipient but unlink failed.";
            }
            return status;
            return PruneStatusT(status);
        }
    }

    return -ENOENT;
    return STATUS_NAME_NOT_FOUND;
}

// start of C-API methods
@@ -323,19 +323,20 @@ bool AIBinder_isAlive(const AIBinder* binder) {

binder_status_t AIBinder_ping(AIBinder* binder) {
    if (binder == nullptr) {
        return EX_NULL_POINTER;
        return STATUS_UNEXPECTED_NULL;
    }

    return binder->getBinder()->pingBinder();
    return PruneStatusT(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 STATUS_UNEXPECTED_NULL;
    }

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

@@ -343,9 +344,10 @@ binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient
                                       void* cookie) {
    if (binder == nullptr || recipient == nullptr) {
        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
        return EX_NULL_POINTER;
        return STATUS_UNEXPECTED_NULL;
    }

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

@@ -406,14 +408,14 @@ void* AIBinder_getUserData(AIBinder* binder) {
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
    if (binder == nullptr || in == nullptr) {
        LOG(ERROR) << __func__ << ": requires non-null parameters.";
        return EX_NULL_POINTER;
        return STATUS_UNEXPECTED_NULL;
    }
    const AIBinder_Class* clazz = binder->getClass();
    if (clazz == nullptr) {
        LOG(ERROR) << __func__
                   << ": Class must be defined for a remote binder transaction. See "
                      "AIBinder_associateClass.";
        return EX_ILLEGAL_STATE;
        return STATUS_INVALID_OPERATION;
    }

    if (!binder->isRemote()) {
@@ -424,20 +426,22 @@ binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) {
    }

    *in = new AParcel(binder);
    binder_status_t status = (**in)->writeInterfaceToken(clazz->getInterfaceDescriptor());
    if (status != EX_NONE) {
    status_t status = (**in)->writeInterfaceToken(clazz->getInterfaceDescriptor());
    binder_status_t ret = PruneStatusT(status);

    if (ret != STATUS_OK) {
        delete *in;
        *in = nullptr;
    }

    return status;
    return ret;
}

binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
                                  AParcel** out, binder_flags_t flags) {
    if (in == nullptr) {
        LOG(ERROR) << __func__ << ": requires non-null in parameter";
        return EX_NULL_POINTER;
        return STATUS_UNEXPECTED_NULL;
    }

    using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>;
@@ -447,36 +451,37 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa

    if (!isUserCommand(code)) {
        LOG(ERROR) << __func__ << ": Only user-defined transactions can be made from the NDK.";
        return EX_UNSUPPORTED_OPERATION;
        return STATUS_UNKNOWN_TRANSACTION;
    }

    if ((flags & ~FLAG_ONEWAY) != 0) {
        LOG(ERROR) << __func__ << ": Unrecognized flags sent: " << flags;
        return EX_ILLEGAL_ARGUMENT;
        return STATUS_BAD_VALUE;
    }

    if (binder == nullptr || *in == nullptr || out == nullptr) {
        LOG(ERROR) << __func__ << ": requires non-null parameters.";
        return EX_NULL_POINTER;
        return STATUS_UNEXPECTED_NULL;
    }

    if ((*in)->getBinder() != binder) {
        LOG(ERROR) << __func__ << ": parcel is associated with binder object " << binder
                   << " but called with " << (*in)->getBinder();
        return EX_ILLEGAL_STATE;
        return STATUS_BAD_VALUE;
    }

    *out = new AParcel(binder);

    binder_status_t parcelStatus =
    status_t status =
            binder->getBinder()->transact(code, *(*in)->operator->(), (*out)->operator->(), flags);
    binder_status_t ret = PruneStatusT(status);

    if (parcelStatus != EX_NONE) {
    if (ret != STATUS_OK) {
        delete *out;
        *out = nullptr;
    }

    return parcelStatus;
    return ret;
}

AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
+2 −2
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ struct ABBinder : public AIBinder, public ::android::BBinder {
    ABBinder* asABBinder() override { return this; }

    const ::android::String16& getInterfaceDescriptor() const override;
    binder_status_t onTransact(uint32_t code, const ::android::Parcel& data,
    ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
                                   ::android::Parcel* reply, binder_flags_t flags) override;

private:
+2 −2
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ typedef struct AIBinder_Class AIBinder_Class;
 *
 * 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.
 * STATUS_DEAD_OBJECT. See also AIBinder_linkToDeath, AIBinder_unlinkToDeath, and AIBinder_isAlive.
 *
 * Once an AIBinder is created, anywhere it is passed (remotely or locally), there is a 1-1
 * correspondence between the address of an AIBinder and the object it represents. This means that
@@ -211,7 +211,7 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient*
/**
 * 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.
 * returns STATUS_NAME_NOT_FOUND.
 */
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
                                       void* cookie);
+37 −10
Original line number Diff line number Diff line
@@ -25,12 +25,42 @@

#pragma once

#include <errno.h>
#include <stdint.h>
#include <sys/cdefs.h>

__BEGIN_DECLS

// Keep the exception codes in sync with android/os/Parcel.java.
enum {
    STATUS_OK = 0,

    STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
    STATUS_NO_MEMORY = -ENOMEM,
    STATUS_INVALID_OPERATION = -ENOSYS,
    STATUS_BAD_VALUE = -EINVAL,
    STATUS_BAD_TYPE = (STATUS_UNKNOWN_ERROR + 1),
    STATUS_NAME_NOT_FOUND = -ENOENT,
    STATUS_PERMISSION_DENIED = -EPERM,
    STATUS_NO_INIT = -ENODEV,
    STATUS_ALREADY_EXISTS = -EEXIST,
    STATUS_DEAD_OBJECT = -EPIPE,
    STATUS_FAILED_TRANSACTION = (STATUS_UNKNOWN_ERROR + 2),
    STATUS_BAD_INDEX = -EOVERFLOW,
    STATUS_NOT_ENOUGH_DATA = -ENODATA,
    STATUS_WOULD_BLOCK = -EWOULDBLOCK,
    STATUS_TIMED_OUT = -ETIMEDOUT,
    STATUS_UNKNOWN_TRANSACTION = -EBADMSG,
    STATUS_FDS_NOT_ALLOWED = (STATUS_UNKNOWN_ERROR + 7),
    STATUS_UNEXPECTED_NULL = (STATUS_UNKNOWN_ERROR + 8),
};

/**
 * One of the STATUS_* values.
 *
 * All unrecognized values are coerced into STATUS_UNKNOWN_ERROR.
 */
typedef int32_t binder_status_t;

enum {
    EX_NONE = 0,
    EX_SECURITY = -1,
@@ -43,12 +73,6 @@ enum {
    EX_SERVICE_SPECIFIC = -8,
    EX_PARCELABLE = -9,

    /**
     * This is special and Java specific; see Parcel.java.
     * This should be considered a success, and the next readInt32 bytes can be ignored.
     */
    EX_HAS_REPLY_HEADER = -128,

    /**
     * This is special, and indicates to native binder proxies that the
     * transaction has failed at a low level.
@@ -57,10 +81,13 @@ enum {
};

/**
 * One of the above values or -errno.
 * By convention, positive values are considered to mean service-specific exceptions.
 * One of the EXCEPTION_* types.
 *
 * All unrecognized values are coerced into EXCEPTION_TRANSACTION_FAILED.
 *
 * These exceptions values are used by the SDK for parcelables. Also see Parcel.java.
 */
typedef int32_t binder_status_t;
typedef int32_t binder_exception_t;

__END_DECLS

Loading