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

Commit 2e87adc8 authored by Steven Moreland's avatar Steven Moreland
Browse files

Initial C library for libbinder.

This creates a simple wrapper around libbinder with a stable C ABI. It
also embeds the concept of an IBinder and IBinder transactions into the
ABI so that parts of their transactions can be changed and considered
implementation details of libbinder. With this basic class, you can
create a service, use it with primitive data types, but it does not yet
suppport the entire range of binder objects.

Follow-up items to handle/things still to consider
- b/112664205: make aidl-gen produce interfaces that use these (and
    think about interoperation with existing interfaces).
- using onServiceConnected/onServiceDisconnected in the NDK
- if libbinder/libbinder_ndk classes use the same descriptor, there will
  be problems in the same process (libbinder{_ndk} assumes binder class)
- sometimes getService takes 1s since there is a race for it getting
  registered
- add generic class which allows for easy implementation of a class like
  IFoo in this test.
- Parcel for additional types (and additional APIs, like data available)
- addition of APIs like AIBinder_ping/linkToDeath which all binders have
- embed Status into this API layer (so EX_HAS_REPLY_HEADER is handled)
- make remoteBinder/localBinder is const (and therefore isRemote)
- okay with associateClass or should just use interfaceDescriptor
- potentially changing out incStrong/decStrong
- adding @file/@addtogroup to comments

Bug: 111445392
Test: ndk/runtests.sh

Change-Id: Ifbca8f0fdf70a3213fe0d94320fc31eeb62408c4
parent 92fdc2c2
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android/binder_process.h>

#include <mutex>

#include <android-base/logging.h>
#include <binder/IPCThreadState.h>

using ::android::IPCThreadState;
using ::android::ProcessState;

void ABinderProcess_startThreadPool() {
    ProcessState::self()->startThreadPool();
    ProcessState::self()->giveThreadPoolName();
}
bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
    return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
}
void ABinderProcess_joinThreadPool() {
    IPCThreadState::self()->joinThreadPool();
}
+345 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android/binder_ibinder.h>
#include "AIBinder_internal.h"

#include <android/binder_status.h>
#include "AParcel_internal.h"

#include <android-base/logging.h>

using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;
using ::android::String16;
using ::android::wp;

AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
AIBinder::~AIBinder() {}

sp<AIBinder> AIBinder::associateClass(const AIBinder_Class* clazz) {
    using ::android::String8;

    if (clazz == nullptr) return nullptr;
    if (mClazz == clazz) return this;

    String8 newDescriptor(clazz->getInterfaceDescriptor());

    if (mClazz != nullptr) {
        String8 currentDescriptor(mClazz->getInterfaceDescriptor());
        if (newDescriptor == currentDescriptor) {
            LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
                       << "' match during associateClass, but they are different class objects. "
                          "Class descriptor collision?";
            return nullptr;
        }

        LOG(ERROR) << __func__
                   << ": Class cannot be associated on object which already has a class. Trying to "
                      "associate to '"
                   << newDescriptor.c_str() << "' but already set to '" << currentDescriptor.c_str()
                   << "'.";
        return nullptr;
    }

    String8 descriptor(getBinder()->getInterfaceDescriptor());
    if (descriptor != newDescriptor) {
        LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor.c_str()
                   << "' but descriptor is actually '" << descriptor.c_str() << "'.";
        return nullptr;
    }

    // The descriptor matches, so if it is local, this is guaranteed to be the libbinder_ndk class.
    // An error here can occur if there is a conflict between descriptors (two unrelated classes
    // define the same descriptor), but this should never happen.

    // if this is a local ABBinder, mClazz should be non-null
    CHECK(asABBinder() == nullptr);
    CHECK(asABpBinder() != nullptr);

    if (!isRemote()) {
        // ABpBinder but proxy to a local object. Therefore that local object must be an ABBinder.
        ABBinder* binder = static_cast<ABBinder*>(getBinder().get());
        return binder;
    }

    // This is a remote object
    mClazz = clazz;

    return this;
}

ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
      : AIBinder(clazz), BBinder(), mUserData(userData) {
    CHECK(clazz != nullptr);
}
ABBinder::~ABBinder() {
    getClass()->onDestroy(mUserData);
}

const String16& ABBinder::getInterfaceDescriptor() const {
    return getClass()->getInterfaceDescriptor();
}

binder_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;
        }

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

        return getClass()->onTransact(this, code, &in, &out);
    } else {
        return BBinder::onTransact(code, data, reply, flags);
    }
}

ABpBinder::ABpBinder(::android::sp<::android::IBinder> binder)
      : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
    CHECK(binder != nullptr);
}
ABpBinder::~ABpBinder() {}

struct AIBinder_Weak {
    wp<AIBinder> binder;
};
AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) {
    if (binder == nullptr) return nullptr;
    return new AIBinder_Weak{wp<AIBinder>(binder)};
}
void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) {
    delete weakBinder;
}
AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) {
    if (weakBinder == nullptr) return nullptr;
    sp<AIBinder> binder = weakBinder->binder.promote();
    AIBinder_incStrong(binder.get());
    return binder.get();
}

AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                               AIBinder_Class_onDestroy onDestroy,
                               AIBinder_Class_onTransact onTransact)
      : onCreate(onCreate),
        onDestroy(onDestroy),
        onTransact(onTransact),
        mInterfaceDescriptor(interfaceDescriptor) {}

AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
                                      AIBinder_Class_onCreate onCreate,
                                      AIBinder_Class_onDestroy onDestroy,
                                      AIBinder_Class_onTransact onTransact) {
    if (interfaceDescriptor == nullptr || onCreate == nullptr || onDestroy == nullptr ||
        onTransact == nullptr) {
        return nullptr;
    }

    return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
}

AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
    if (clazz == nullptr) {
        LOG(ERROR) << __func__ << ": Must provide class to construct local binder.";
        return nullptr;
    }

    void* userData = clazz->onCreate(args);

    AIBinder* ret = new ABBinder(clazz, userData);
    AIBinder_incStrong(ret);
    return ret;
}

bool AIBinder_isRemote(AIBinder* binder) {
    if (binder == nullptr) {
        return true;
    }

    return binder->isRemote();
}

void AIBinder_incStrong(AIBinder* binder) {
    if (binder == nullptr) {
        LOG(ERROR) << __func__ << ": on null binder";
        return;
    }

    binder->incStrong(nullptr);
}
void AIBinder_decStrong(AIBinder* binder) {
    if (binder == nullptr) {
        LOG(ERROR) << __func__ << ": on null binder";
        return;
    }

    binder->decStrong(nullptr);
}
int32_t AIBinder_debugGetRefCount(AIBinder* binder) {
    if (binder == nullptr) {
        LOG(ERROR) << __func__ << ": on null binder";
        return -1;
    }

    return binder->getStrongCount();
}

void AIBinder_associateClass(AIBinder** binder, const AIBinder_Class* clazz) {
    if (binder == nullptr || *binder == nullptr) {
        return;
    }

    sp<AIBinder> result = (*binder)->associateClass(clazz);

    // This function takes one refcount of 'binder' and delivers one refcount of 'result' to the
    // callee. First we give the callee their refcount and then take it away from binder. This is
    // done in this order in order to handle the case that the result and the binder are the same
    // object.
    if (result != nullptr) {
        AIBinder_incStrong(result.get());
    }
    AIBinder_decStrong(*binder);

    *binder = result.get(); // Maybe no-op
}

const AIBinder_Class* AIBinder_getClass(AIBinder* binder) {
    if (binder == nullptr) {
        return nullptr;
    }

    return binder->getClass();
}

void* AIBinder_getUserData(AIBinder* binder) {
    if (binder == nullptr) {
        return nullptr;
    }

    ABBinder* bBinder = binder->asABBinder();
    if (bBinder == nullptr) {
        return nullptr;
    }

    return bBinder->getUserData();
}

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;
    }
    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;
    }

    *in = new AParcel(binder);
    binder_status_t status = (**in)->writeInterfaceToken(clazz->getInterfaceDescriptor());
    if (status != EX_NONE) {
        delete *in;
        *in = nullptr;
    }

    return status;
}

using AutoParcelDestroyer = std::unique_ptr<AParcel*, void (*)(AParcel**)>;
static void destroy_parcel(AParcel** parcel) {
    delete *parcel;
    *parcel = nullptr;
}

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;
    }

    // This object is the input to the transaction. This function takes ownership of it and deletes
    // it.
    AutoParcelDestroyer forIn(in, destroy_parcel);

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

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

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

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

    *out = new AParcel(binder);

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

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

    return parcelStatus;
}

binder_status_t AIBinder_finalizeTransaction(AIBinder* binder, AParcel** out) {
    if (out == nullptr) {
        LOG(ERROR) << __func__ << ": requires non-null out parameter";
        return EX_NULL_POINTER;
    }

    // This object is the input to the transaction. This function takes ownership of it and deletes
    // it.
    AutoParcelDestroyer forOut(out, destroy_parcel);

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

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

    if ((**out)->dataAvail() != 0) {
        LOG(ERROR) << __func__
                   << ": Only part of this transaction was read. There is remaining data left.";
        return EX_ILLEGAL_STATE;
    }

    return EX_NONE;
}
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <android/binder_ibinder.h>
#include "AIBinder_internal.h"

#include <atomic>

#include <binder/Binder.h>
#include <binder/IBinder.h>

inline bool isUserCommand(transaction_code_t code) {
    return code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION;
}

struct ABBinder;
struct ABpBinder;

struct AIBinder : public virtual ::android::RefBase {
    AIBinder(const AIBinder_Class* clazz);
    virtual ~AIBinder();

    // This returns an AIBinder object with this class associated. If the class is already
    // associated, 'this' will be returned. If there is a local AIBinder implementation, that will
    // be returned. If this is a remote object, the class will be associated and this will be ready
    // to be used for transactions.
    ::android::sp<AIBinder> associateClass(const AIBinder_Class* clazz);
    const AIBinder_Class* getClass() const { return mClazz; }

    // This does not create the binder if it does not exist in the process.
    virtual ::android::sp<::android::IBinder> getBinder() = 0;
    virtual ABBinder* asABBinder() { return nullptr; }
    virtual ABpBinder* asABpBinder() { return nullptr; }

    bool isRemote() {
        auto binder = getBinder();
        // if the binder is nullptr, then it is a local object which hasn't been sent out of process
        // yet.
        return binder != nullptr && binder->remoteBinder() != nullptr;
    }

private:
    // AIBinder instance is instance of this class for a local object. In order to transact on a
    // remote object, this also must be set for simplicity (although right now, only the
    // interfaceDescriptor from it is used).
    const AIBinder_Class* mClazz;
};

// This is a local AIBinder object with a known class.
struct ABBinder : public AIBinder, public ::android::BBinder {
    ABBinder(const AIBinder_Class* clazz, void* userData);
    virtual ~ABBinder();

    void* getUserData() { return mUserData; }

    ::android::sp<::android::IBinder> getBinder() override { return this; }
    ABBinder* asABBinder() override { return this; }

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

private:
    // Can contain implementation if this is a local binder. This can still be nullptr for a local
    // binder. If it is nullptr, the implication is the implementation state is entirely external to
    // this object and the functionality provided in the AIBinder_Class is sufficient.
    void* mUserData;
};

// This binder object may be remote or local (even though it is 'Bp'). It is not yet associated with
// a class.
struct ABpBinder : public AIBinder, public ::android::BpRefBase {
    ABpBinder(::android::sp<::android::IBinder> binder);
    virtual ~ABpBinder();

    ::android::sp<::android::IBinder> getBinder() override { return remote(); }
    ABpBinder* asABpBinder() override { return this; }
};

struct AIBinder_Class {
    AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
                   AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact);

    const ::android::String16& getInterfaceDescriptor() const { return mInterfaceDescriptor; }

    const AIBinder_Class_onCreate onCreate;
    const AIBinder_Class_onDestroy onDestroy;
    const AIBinder_Class_onTransact onTransact;

private:
    // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
    // one.
    const ::android::String16 mInterfaceDescriptor;
};
+127 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android/binder_parcel.h>
#include "AParcel_internal.h"

#include "AIBinder_internal.h"

#include <binder/Parcel.h>

using ::android::IBinder;
using ::android::Parcel;
using ::android::sp;

binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
    return (*parcel)->writeStrongBinder(binder->getBinder());
}
binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
    sp<IBinder> readBinder = nullptr;
    binder_status_t status = (*parcel)->readStrongBinder(&readBinder);
    if (status != EX_NONE) {
        return status;
    }
    *binder = new ABpBinder(readBinder);
    AIBinder_incStrong(*binder);
    return status;
}
binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) {
    sp<IBinder> readBinder = nullptr;
    binder_status_t status = (*parcel)->readNullableStrongBinder(&readBinder);
    if (status != EX_NONE) {
        return status;
    }
    *binder = new ABpBinder(readBinder);
    AIBinder_incStrong(*binder);
    return status;
}

// See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
// libbinder and this library.
// @START
binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) {
    return (*parcel)->writeInt32(value);
}

binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) {
    return (*parcel)->writeUint32(value);
}

binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) {
    return (*parcel)->writeInt64(value);
}

binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) {
    return (*parcel)->writeUint64(value);
}

binder_status_t AParcel_writeFloat(AParcel* parcel, float value) {
    return (*parcel)->writeFloat(value);
}

binder_status_t AParcel_writeDouble(AParcel* parcel, double value) {
    return (*parcel)->writeDouble(value);
}

binder_status_t AParcel_writeBool(AParcel* parcel, bool value) {
    return (*parcel)->writeBool(value);
}

binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) {
    return (*parcel)->writeChar(value);
}

binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) {
    return (*parcel)->writeByte(value);
}

binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) {
    return (*parcel)->readInt32(value);
}

binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) {
    return (*parcel)->readUint32(value);
}

binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) {
    return (*parcel)->readInt64(value);
}

binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) {
    return (*parcel)->readUint64(value);
}

binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) {
    return (*parcel)->readFloat(value);
}

binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) {
    return (*parcel)->readDouble(value);
}

binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) {
    return (*parcel)->readBool(value);
}

binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) {
    return (*parcel)->readChar(value);
}

binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) {
    return (*parcel)->readByte(value);
}

// @END
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <android/binder_parcel.h>

#include <sys/cdefs.h>

#include <binder/Parcel.h>
#include "AIBinder_internal.h"

struct AParcel {
    const ::android::Parcel* operator->() const { return mParcel; }
    ::android::Parcel* operator->() { return mParcel; }

    AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
    AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
          : mBinder(binder), mParcel(parcel), mOwns(owns) {}

    ~AParcel() {
        if (mOwns) {
            delete mParcel;
        }
    }

    static const AParcel readOnly(const AIBinder* binder, const ::android::Parcel* parcel) {
        return AParcel(binder, const_cast<::android::Parcel*>(parcel), false);
    }

    const AIBinder* getBinder() { return mBinder; }

private:
    // This object is associated with a calls to a specific AIBinder object. This is used for sanity
    // checking to make sure that a parcel is one that is expected.
    const AIBinder* mBinder;

    ::android::Parcel* mParcel;
    bool mOwns;
};
Loading