diff options
21 files changed, 1819 insertions, 0 deletions
diff --git a/libs/binder/ndk/ABinderProcess.cpp b/libs/binder/ndk/ABinderProcess.cpp new file mode 100644 index 0000000000..c89caaf349 --- /dev/null +++ b/libs/binder/ndk/ABinderProcess.cpp @@ -0,0 +1,36 @@ +/* + * 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(); +} diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/AIBinder.cpp new file mode 100644 index 0000000000..d0ce98db93 --- /dev/null +++ b/libs/binder/ndk/AIBinder.cpp @@ -0,0 +1,345 @@ +/* + * 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; +} diff --git a/libs/binder/ndk/AIBinder_internal.h b/libs/binder/ndk/AIBinder_internal.h new file mode 100644 index 0000000000..d44b937ec7 --- /dev/null +++ b/libs/binder/ndk/AIBinder_internal.h @@ -0,0 +1,109 @@ +/* + * 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; +}; diff --git a/libs/binder/ndk/AParcel.cpp b/libs/binder/ndk/AParcel.cpp new file mode 100644 index 0000000000..b63b138dc4 --- /dev/null +++ b/libs/binder/ndk/AParcel.cpp @@ -0,0 +1,127 @@ +/* + * 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 diff --git a/libs/binder/ndk/AParcel_internal.h b/libs/binder/ndk/AParcel_internal.h new file mode 100644 index 0000000000..9f30a2faf1 --- /dev/null +++ b/libs/binder/ndk/AParcel_internal.h @@ -0,0 +1,53 @@ +/* + * 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; +}; diff --git a/libs/binder/ndk/AServiceManager.cpp b/libs/binder/ndk/AServiceManager.cpp new file mode 100644 index 0000000000..f61b914089 --- /dev/null +++ b/libs/binder/ndk/AServiceManager.cpp @@ -0,0 +1,47 @@ +/* + * 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_manager.h> +#include "AIBinder_internal.h" + +#include <binder/IServiceManager.h> + +using ::android::defaultServiceManager; +using ::android::IBinder; +using ::android::IServiceManager; +using ::android::sp; +using ::android::String16; + +binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance) { + if (binder == nullptr || instance == nullptr) { + return EX_NULL_POINTER; + } + + sp<IServiceManager> sm = defaultServiceManager(); + return sm->addService(String16(instance), binder->getBinder()); +} +AIBinder* AServiceManager_getService(const char* instance) { + if (instance == nullptr) { + return nullptr; + } + + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16(instance)); + + AIBinder* ret = new ABpBinder(binder); + AIBinder_incStrong(ret); + return ret; +} diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp new file mode 100644 index 0000000000..76d5a73063 --- /dev/null +++ b/libs/binder/ndk/Android.bp @@ -0,0 +1,38 @@ +/* + * 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. + */ + +cc_library { + name: "libbinder_ndk", + vendor_available: false, + + export_include_dirs: [ + "include_ndk", + "include_apex", + ], + + srcs: [ + "ABinderProcess.cpp", + "AIBinder.cpp", + "AParcel.cpp", + "AServiceManager.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", + "libutils", + ], +} diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h new file mode 100644 index 0000000000..b8f38ba88b --- /dev/null +++ b/libs/binder/ndk/include_apex/android/binder_manager.h @@ -0,0 +1,35 @@ +/* + * 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> + +__BEGIN_DECLS + +/** + * This registers the service with the default service manager under this instance name. + */ +binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance); + +/** + * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on + * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible + * for calling AIBinder_decStrong). + */ +__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance); + +__END_DECLS diff --git a/libs/binder/ndk/include_apex/android/binder_process.h b/libs/binder/ndk/include_apex/android/binder_process.h new file mode 100644 index 0000000000..69e6387bcb --- /dev/null +++ b/libs/binder/ndk/include_apex/android/binder_process.h @@ -0,0 +1,40 @@ +/* + * 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 <stdint.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * This creates a threadpool for incoming binder transactions if it has not already been created. + */ +void ABinderProcess_startThreadPool(); +/** + * This sets the maximum number of threads that can be started in the threadpool. By default, after + * startThreadPool is called, this is one. If it is called additional times, it will only prevent + * the kernel from starting new threads and will not delete already existing threads. + */ +bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads); +/** + * This adds the current thread to the threadpool. This may cause the threadpool to exceed the + * maximum size. + */ +void ABinderProcess_joinThreadPool(); + +__END_DECLS diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h new file mode 100644 index 0000000000..23136a2de8 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -0,0 +1,247 @@ +/* + * 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 <stdint.h> +#include <sys/cdefs.h> + +#include <android/binder_parcel.h> +#include <android/binder_status.h> + +__BEGIN_DECLS + +// Also see TF_* in kernel's binder.h +typedef uint32_t binder_flags_t; +enum { + /** + * The transaction will be dispatched and then returned to the caller. The outgoing process + * cannot block a call made by this, and execution of the call will not be waited on. An error + * can still be returned if the call is unable to be processed by the binder driver. All oneway + * calls are guaranteed to be ordered if they are sent on the same AIBinder object. + */ + FLAG_ONEWAY = 0x01, +}; + +// Also see IBinder.h in libbinder +typedef uint32_t transaction_code_t; +enum { + /** + * The first transaction code available for user commands (inclusive). + */ + FIRST_CALL_TRANSACTION = 0x00000001, + /** + * The last transaction code available for user commands (inclusive). + */ + LAST_CALL_TRANSACTION = 0x00ffffff, +}; + +/** + * Represents a type of AIBinder object which can be sent out. + */ +struct AIBinder_Class; +typedef struct AIBinder_Class AIBinder_Class; + +/** + * Represents a local or remote object which can be used for IPC or which can itself be sent. + * + * This object has a refcount associated with it and will be deleted when its refcount reaches zero. + * How methods interactive with this refcount is described below. When using this API, it is + * intended for a client of a service to hold a strong reference to that service. This also means + * that user data typically should hold a strong reference to a local AIBinder object. A remote + * AIBinder object automatically holds a strong reference to the AIBinder object in the server's + * process. A typically memory layout looks like this: + * + * Key: + * ---> Ownership/a strong reference + * ...> A weak reference + * + * (process boundary) + * | + * MyInterface ---> AIBinder_Weak | ProxyForMyInterface + * ^ . | | + * | . | | + * | v | v + * UserData <--- AIBinder <-|- AIBinder + * | + * + * In this way, you'll notice that a proxy for the interface holds a strong reference to the + * implementation and that in the server process, the AIBinder object which was sent can be resent + * so that the same AIBinder object always represents the same object. This allows, for instance, an + * 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. + */ +struct AIBinder; +typedef struct AIBinder AIBinder; + +/** + * The AIBinder object associated with this can be retrieved if it is still alive so that it can be + * re-used. The intention of this is to enable the same AIBinder object to always represent the same + * object. + */ +struct AIBinder_Weak; +typedef struct AIBinder_Weak AIBinder_Weak; + +/** + * This is called whenever a new AIBinder object is needed of a specific class. + * + * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved + * using AIBinder_getUserData. + */ +typedef void* (*AIBinder_Class_onCreate)(void* args); + +/** + * This is called whenever an AIBinder object is no longer referenced and needs destroyed. + * + * Typically, this just deletes whatever the implementation is. + */ +typedef void (*AIBinder_Class_onDestroy)(void* userData); + +/** + * This is called whenever a transaction needs to be processed by a local implementation. + */ +typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code, + const AParcel* in, AParcel* out); + +/** + * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used + * internally for sanity checks on transactions. + * + * None of these parameters can be nullptr. + * + * This is created one time during library initialization and cleaned up when the process exits or + * execs. + */ +__attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define( + const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, + AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact); + +/** + * Creates a new binder object of the appropriate class. + * + * Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong + * and AIBinder_decStrong. When the reference count reaches zero, onDestroy is called. + * + * When this is called, the refcount is implicitly 1. So, calling decStrong exactly one time is + * required to delete this object. + */ +__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args); + +/** + * If this is hosted in a process other than the current one. + */ +bool AIBinder_isRemote(AIBinder* binder); + +/** + * This can only be called if a strong reference to this object already exists in process. + */ +void AIBinder_incStrong(AIBinder* binder); + +/** + * This will delete the object and call onDestroy once the refcount reaches zero. + */ +void AIBinder_decStrong(AIBinder* binder); + +/** + * For debugging only! + */ +int32_t AIBinder_debugGetRefCount(AIBinder* binder); + +/** + * This sets the class of an AIBinder object. This checks to make sure the remote object is of + * the expected class. A class must be set in order to use transactions on an AIBinder object. + * However, if an object is just intended to be passed through to another process or used as a + * handle this need not be called. + * + * The binder parameter may or may not be updated. If it is updated, the ownership of the original + * object is transferred to the new object. If the class association fails, ownership of the binder + * is lost, and it is set to nullptr. + */ +void AIBinder_associateClass(AIBinder** binder, const AIBinder_Class* clazz); + +/* + * Returns the class that this binder was constructed with or associated with. + */ +const AIBinder_Class* AIBinder_getClass(AIBinder* binder); + +/** + * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns + * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr. + */ +void* AIBinder_getUserData(AIBinder* binder); + +/** + * A transaction is a series of calls to these functions which looks this + * - call AIBinder_prepareTransaction + * - fill out parcel with in parameters (lifetime of the 'in' variable) + * - call AIBinder_transact + * - fill out parcel with out parameters (lifetime of the 'out' variable) + * - call AIBinder_finalizeTransaction + */ + +/** + * Creates a parcel to start filling out for a transaction. This may add data to the parcel for + * security, debugging, or other purposes. This parcel is to be sent via AIBinder_transact and it + * represents the input data to the transaction. It is recommended to check if the object is local + * and call directly into its user data before calling this as the parceling and unparceling cost + * can be avoided. This AIBinder must be either built with a class or associated with a class before + * using this API. + * + * This does not affect the ownership of binder. + */ +binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in); + +/** + * Transact using a parcel created from AIBinder_prepareTransaction. This actually communicates with + * the object representing this binder object. This also passes out a parcel to be used for the + * return transaction. This takes ownership of the in parcel and automatically deletes it after it + * is sent to the remote process. The output parcel is the result of the transaction. If the + * transaction has FLAG_ONEWAY, the out parcel will be empty. Otherwise, this will block until the + * remote process has processed the transaction, and the out parcel will contain the output data + * from transaction. + * + * This does not affect the ownership of binder. + */ +binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in, + AParcel** out, binder_flags_t flags); + +/** + * This takes ownership of the out parcel and automatically deletes it. Additional checks for + * security or debugging maybe performed internally. + * + * This does not affect the ownership of binder. + */ +binder_status_t AIBinder_finalizeTransaction(AIBinder* binder, AParcel** out); + +/* + * This does not take any ownership of the input binder, but it can be used to retrieve it if + * something else in some process still holds a reference to it. + */ +__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder); + +/* + * Deletes the weak reference. This will have no impact on the lifetime of the binder. + */ +void AIBinder_Weak_delete(AIBinder_Weak* weakBinder); + +/** + * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns + * nullptr. + */ +__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder); + +__END_DECLS diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h new file mode 100644 index 0000000000..091ae8ec95 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -0,0 +1,147 @@ +/* + * 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 <sys/cdefs.h> + +#include <android/binder_status.h> + +struct AIBinder; +typedef struct AIBinder AIBinder; + +__BEGIN_DECLS + +/** + * This object represents a package of data that can be sent between processes. When transacting, an + * instance of it is automatically created to be used for the transaction. When two processes use + * binder to communicate, they must agree on a format of this parcel to be used in order to transfer + * data. This is usually done in an IDL (see AIDL, specificially). + */ +struct AParcel; +typedef struct AParcel AParcel; + +/** + * Writes an AIBinder to the next location in a non-null parcel. Can be null. + */ +binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder); + +/** + * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is + * non-null. One strong ref-count of ownership is passed to the caller of this function. + */ +binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder); + +/** + * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong + * ref-count of ownership is passed to the caller of this function. + */ +binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder); + +// @START +/** + * Writes int32_t value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value); + +/** + * Writes uint32_t value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value); + +/** + * Writes int64_t value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value); + +/** + * Writes uint64_t value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value); + +/** + * Writes float value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeFloat(AParcel* parcel, float value); + +/** + * Writes double value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeDouble(AParcel* parcel, double value); + +/** + * Writes bool value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeBool(AParcel* parcel, bool value); + +/** + * Writes char16_t value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value); + +/** + * Writes int8_t value to the next location in a non-null parcel. + */ +binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value); + +/** + * Reads into int32_t value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value); + +/** + * Reads into uint32_t value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value); + +/** + * Reads into int64_t value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value); + +/** + * Reads into uint64_t value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value); + +/** + * Reads into float value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readFloat(const AParcel* parcel, float* value); + +/** + * Reads into double value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readDouble(const AParcel* parcel, double* value); + +/** + * Reads into bool value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readBool(const AParcel* parcel, bool* value); + +/** + * Reads into char16_t value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value); + +/** + * Reads into int8_t value from the next location in a non-null parcel. + */ +binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value); + +// @END + +__END_DECLS diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h new file mode 100644 index 0000000000..d414c99ef9 --- /dev/null +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -0,0 +1,56 @@ +/* + * 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 <stdint.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +// Keep the exception codes in sync with android/os/Parcel.java. +enum { + EX_NONE = 0, + EX_SECURITY = -1, + EX_BAD_PARCELABLE = -2, + EX_ILLEGAL_ARGUMENT = -3, + EX_NULL_POINTER = -4, + EX_ILLEGAL_STATE = -5, + EX_NETWORK_MAIN_THREAD = -6, + EX_UNSUPPORTED_OPERATION = -7, + 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. + */ + EX_TRANSACTION_FAILED = -129, +}; + +/** + * One of the above values or -errno. + * By convention, positive values are considered to mean service-specific exceptions. + */ +typedef int32_t binder_status_t; + +__END_DECLS diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh new file mode 100755 index 0000000000..6c8527d6f7 --- /dev/null +++ b/libs/binder/ndk/runtests.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# 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. + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi + +set -ex + +function run_libbinder_ndk_test() { + adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & + local pid=$! + trap "kill $pid" ERR + adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client + trap '' ERR + kill $pid +} + +[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ + MODULES-IN-frameworks-native-libs-binder-ndk + +adb root +adb wait-for-device +adb sync data + +run_libbinder_ndk_test diff --git a/libs/binder/ndk/scripts/format.sh b/libs/binder/ndk/scripts/format.sh new file mode 100755 index 0000000000..698d291cb1 --- /dev/null +++ b/libs/binder/ndk/scripts/format.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# 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. + +set -e + +echo "Formatting code" + +bpfmt -w $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -name "Android.bp") +clang-format -i $(find $ANDROID_BUILD_TOP/frameworks/native/libs/binder/ndk/ -\( -name "*.cpp" -o -name "*.h" -\)) diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py new file mode 100755 index 0000000000..5c0b936cf7 --- /dev/null +++ b/libs/binder/ndk/scripts/gen_parcel_helper.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +# 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. + +import os +import sys + +# list (pretty, cpp) +data_types = [ + ("Int32", "int32_t"), + ("Uint32", "uint32_t"), + ("Int64", "int64_t"), + ("Uint64", "uint64_t"), + ("Float", "float"), + ("Double", "double"), + ("Bool", "bool"), + ("Char", "char16_t"), + ("Byte", "int8_t"), +] + +def replaceFileTags(path, content): + print("Updating", path) + with open(path, "r+") as f: + lines = f.readlines() + + start = lines.index("// @START\n") + end = lines.index("// @END\n") + + if end <= start or start < 0 or end < 0: + print("Failed to find tags in", path) + exit(1) + + f.seek(0) + f.write("".join(lines[:start+1]) + content + "".join(lines[end:])) + f.truncate() + +def main(): + if len(sys.argv) != 1: + print("No arguments.") + exit(1) + + ABT = os.environ.get('ANDROID_BUILD_TOP', None) + if ABT is None: + print("Can't get ANDROID_BUILD_TOP. Lunch?") + exit(1) + ROOT = ABT + "/frameworks/native/libs/binder/ndk/" + + print("Updating auto-generated code") + + header = "" + source = "" + + for pretty, cpp in data_types: + header += "/**\n" + header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n" + header += " */\n" + header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value);\n\n" + source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n" + source += " return (*parcel)->write" + pretty + "(value);\n" + source += "}\n\n" + + for pretty, cpp in data_types: + header += "/**\n" + header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n" + header += " */\n" + header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value);\n\n" + source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n" + source += " return (*parcel)->read" + pretty + "(value);\n" + source += "}\n\n" + + replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header) + replaceFileTags(ROOT + "AParcel.cpp", source) + + print("Updating DONE.") + +if __name__ == "__main__": + main() diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp new file mode 100644 index 0000000000..d2421389f2 --- /dev/null +++ b/libs/binder/ndk/test/Android.bp @@ -0,0 +1,68 @@ +/* + * 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. + */ + +// This test is a unit test of the low-level API that is presented here. +// Actual users should use AIDL to generate these complicated stubs. + +cc_defaults { + name: "test_libbinder_ndk_defaults", + shared_libs: [ + "libbase", + ], + strip: { + none: true, + }, + cflags: [ + "-O0", + "-g", + ], +} + +cc_library_static { + name: "test_libbinder_ndk_library", + defaults: ["test_libbinder_ndk_defaults"], + export_include_dirs: ["include"], + shared_libs: ["libbinder_ndk"], + export_shared_lib_headers: ["libbinder_ndk"], + srcs: ["iface.cpp"], +} + +cc_defaults { + name: "test_libbinder_ndk_test_defaults", + defaults: ["test_libbinder_ndk_defaults"], + shared_libs: [ + "libbase", + "libbinder", + "libutils", + ], + static_libs: [ + "libbinder_ndk", + "test_libbinder_ndk_library", + ], +} + +cc_test { + name: "libbinder_ndk_test_client", + defaults: ["test_libbinder_ndk_test_defaults"], + srcs: ["main_client.cpp"], +} + +cc_test { + name: "libbinder_ndk_test_server", + defaults: ["test_libbinder_ndk_test_defaults"], + srcs: ["main_server.cpp"], + gtest: false, +} diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp new file mode 100644 index 0000000000..eed09f02c7 --- /dev/null +++ b/libs/binder/ndk/test/iface.cpp @@ -0,0 +1,145 @@ +/* + * 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-base/logging.h> +#include <android/binder_manager.h> +#include <iface/iface.h> + +using ::android::sp; +using ::android::wp; + +const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo"; +const char* kIFooDescriptor = "my-special-IFoo-class"; + +struct IFoo_Class_Data { + sp<IFoo> foo; +}; + +void* IFoo_Class_onCreate(void* args) { + IFoo_Class_Data* foo = static_cast<IFoo_Class_Data*>(args); + // This is a foo, but we're currently not verifying that. So, the method newLocalBinder is + // coupled with this. + return static_cast<void*>(foo); +} + +void IFoo_Class_onDestroy(void* userData) { + delete static_cast<IFoo_Class_Data*>(userData); +} + +binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, const AParcel* in, + AParcel* out) { + binder_status_t stat = EX_UNSUPPORTED_OPERATION; + + sp<IFoo> foo = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder))->foo; + CHECK(foo != nullptr) << "Transaction made on already deleted object"; + + switch (code) { + case IFoo::DOFOO: { + int32_t valueIn; + stat = AParcel_readInt32(in, &valueIn); + if (stat != EX_NONE) break; + int32_t valueOut = foo->doubleNumber(valueIn); + stat = AParcel_writeInt32(out, valueOut); + break; + } + } + + return stat; +} + +AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate, + IFoo_Class_onDestroy, IFoo_Class_onTransact); + +class BpFoo : public IFoo { +public: + BpFoo(AIBinder* binder) : mBinder(binder) {} + virtual ~BpFoo() { AIBinder_decStrong(mBinder); } + + virtual int32_t doubleNumber(int32_t in) { + AParcel* parcelIn; + CHECK(EX_NONE == AIBinder_prepareTransaction(mBinder, &parcelIn)); + + CHECK(EX_NONE == AParcel_writeInt32(parcelIn, in)); + + AParcel* parcelOut; + CHECK(EX_NONE == + AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/)); + + int32_t out; + CHECK(EX_NONE == AParcel_readInt32(parcelOut, &out)); + + CHECK(EX_NONE == AIBinder_finalizeTransaction(mBinder, &parcelOut)); + return out; + } + +private: + // Always assumes one refcount + AIBinder* mBinder; +}; + +IFoo::~IFoo() { + AIBinder_Weak_delete(mWeakBinder); +} + +binder_status_t IFoo::addService(const char* instance) { + AIBinder* binder = nullptr; + + if (mWeakBinder != nullptr) { + // one strong ref count of binder + binder = AIBinder_Weak_promote(mWeakBinder); + } + if (binder == nullptr) { + // or one strong refcount here + binder = AIBinder_new(IFoo::kClass, static_cast<void*>(new IFoo_Class_Data{this})); + if (mWeakBinder != nullptr) { + AIBinder_Weak_delete(mWeakBinder); + } + mWeakBinder = AIBinder_Weak_new(binder); + } + + binder_status_t status = AServiceManager_addService(binder, instance); + // Strong references we care about kept by remote process + AIBinder_decStrong(binder); + return status; +} + +sp<IFoo> IFoo::getService(const char* instance) { + AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr + AIBinder_associateClass(&binder, IFoo::kClass); + + if (binder == nullptr) { + return nullptr; + } + + if (AIBinder_isRemote(binder)) { + sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder + return ret; + } + + IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder)); + + CHECK(data != nullptr); // always created with non-null data + + sp<IFoo> ret = data->foo; + + AIBinder* held = AIBinder_Weak_promote(ret->mWeakBinder); + CHECK(held == binder); + AIBinder_decStrong(held); + + // IFoo only keeps a weak reference to AIBinder, so we can drop this + AIBinder_decStrong(binder); + return ret; +} diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h new file mode 100644 index 0000000000..4c61e9d849 --- /dev/null +++ b/libs/binder/ndk/test/include/iface/iface.h @@ -0,0 +1,40 @@ +/* + * 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 <utils/RefBase.h> + +class IFoo : public virtual ::android::RefBase { +public: + static const char* kSomeInstanceName; + static AIBinder_Class* kClass; + + // Takes ownership of IFoo + binder_status_t addService(const char* instance); + static ::android::sp<IFoo> getService(const char* instance); + + enum Call { + DOFOO = FIRST_CALL_TRANSACTION + 0, + }; + + virtual ~IFoo(); + virtual int32_t doubleNumber(int32_t in) = 0; + +private: + AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder +}; diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp new file mode 100644 index 0000000000..7c53e512fe --- /dev/null +++ b/libs/binder/ndk/test/main_client.cpp @@ -0,0 +1,70 @@ +/* + * 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-base/logging.h> +#include <android/binder_manager.h> +#include <gtest/gtest.h> +#include <iface/iface.h> + +using ::android::sp; + +constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; + +// This is too slow +// TEST(NdkBinder, GetServiceThatDoesntExist) { +// sp<IFoo> foo = IFoo::getService("asdfghkl;"); +// EXPECT_EQ(nullptr, foo.get()); +// } + +TEST(NdkBinder, DoubleNumber) { + sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); + ASSERT_NE(foo, nullptr); + EXPECT_EQ(2, foo->doubleNumber(1)); +} + +TEST(NdkBinder, RetrieveNonNdkService) { + AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); + ASSERT_NE(nullptr, binder); + AIBinder_decStrong(binder); +} + +class MyTestFoo : public IFoo { + int32_t doubleNumber(int32_t in) override { + LOG(INFO) << "doubleNumber " << in; + return 2 * in; + } +}; + +TEST(NdkBinder, GetServiceInProcess) { + static const char* kInstanceName = "test-get-service-in-process"; + + sp<IFoo> foo = new MyTestFoo; + EXPECT_EQ(EX_NONE, foo->addService(kInstanceName)); + + sp<IFoo> getFoo = IFoo::getService(kInstanceName); + EXPECT_EQ(foo.get(), getFoo.get()); + + EXPECT_EQ(2, getFoo->doubleNumber(1)); +} + +TEST(NdkBinder, AddServiceMultipleTimes) { + static const char* kInstanceName1 = "test-multi-1"; + static const char* kInstanceName2 = "test-multi-2"; + sp<IFoo> foo = new MyTestFoo; + EXPECT_EQ(EX_NONE, foo->addService(kInstanceName1)); + EXPECT_EQ(EX_NONE, foo->addService(kInstanceName2)); + EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); +} diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp new file mode 100644 index 0000000000..f3da7dafa1 --- /dev/null +++ b/libs/binder/ndk/test/main_server.cpp @@ -0,0 +1,43 @@ +/* + * 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-base/logging.h> +#include <android/binder_process.h> +#include <iface/iface.h> + +using ::android::sp; + +class MyFoo : public IFoo { + int32_t doubleNumber(int32_t in) override { + LOG(INFO) << "doubling " << in; + return 2 * in; + } +}; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + + // Strong reference to MyFoo kept by service manager. + binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName); + + if (status != EX_NONE) { + LOG(FATAL) << "Could not register: " << status; + } + + ABinderProcess_joinThreadPool(); + + return 1; +} diff --git a/libs/binder/ndk/update.sh b/libs/binder/ndk/update.sh new file mode 100755 index 0000000000..1eba892021 --- /dev/null +++ b/libs/binder/ndk/update.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# 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. + + +set -ex + +# This script makes sure that the source code is in sync with the various scripts +./scripts/gen_parcel_helper.py +./scripts/format.sh |