diff options
Diffstat (limited to 'libs/binder/ndk/tests/iface.cpp')
-rw-r--r-- | libs/binder/ndk/tests/iface.cpp | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp new file mode 100644 index 0000000000..2afe5d2058 --- /dev/null +++ b/libs/binder/ndk/tests/iface.cpp @@ -0,0 +1,186 @@ +/* + * 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> + +#include <android/binder_auto_utils.h> + +using ::android::sp; +using ::android::wp; + +const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo"; +const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die"; +const char* IFoo::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 = STATUS_FAILED_TRANSACTION; + + 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; + int32_t valueOut; + stat = AParcel_readInt32(in, &valueIn); + if (stat != STATUS_OK) break; + stat = foo->doubleNumber(valueIn, &valueOut); + if (stat != STATUS_OK) break; + stat = AParcel_writeInt32(out, valueOut); + break; + } + case IFoo::DIE: { + stat = foo->die(); + 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: + explicit BpFoo(AIBinder* binder) : mBinder(binder) {} + virtual ~BpFoo() { AIBinder_decStrong(mBinder); } + + virtual binder_status_t doubleNumber(int32_t in, int32_t* out) { + binder_status_t stat = STATUS_OK; + + AParcel* parcelIn; + stat = AIBinder_prepareTransaction(mBinder, &parcelIn); + if (stat != STATUS_OK) return stat; + + stat = AParcel_writeInt32(parcelIn, in); + if (stat != STATUS_OK) return stat; + + ::ndk::ScopedAParcel parcelOut; + stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/); + if (stat != STATUS_OK) return stat; + + stat = AParcel_readInt32(parcelOut.get(), out); + if (stat != STATUS_OK) return stat; + + return stat; + } + + virtual binder_status_t die() { + binder_status_t stat = STATUS_OK; + + AParcel* parcelIn; + stat = AIBinder_prepareTransaction(mBinder, &parcelIn); + + ::ndk::ScopedAParcel parcelOut; + stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/); + + return stat; + } + + private: + // Always assumes one refcount + AIBinder* mBinder; +}; + +IFoo::~IFoo() { + AIBinder_Weak_delete(mWeakBinder); +} + +AIBinder* IFoo::getBinder() { + 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); + + // WARNING: it is important that this class does not implement debug or + // shell functions because it does not use special C++ wrapper + // functions, and so this is how we test those functions. + } + + return binder; +} + +binder_status_t IFoo::addService(const char* instance) { + AIBinder* binder = getBinder(); + + 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** outBinder) { + AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr + if (binder == nullptr) { + return nullptr; + } + + if (!AIBinder_associateClass(binder, IFoo::kClass)) { + AIBinder_decStrong(binder); + return nullptr; + } + + if (outBinder != nullptr) { + AIBinder_incStrong(binder); + *outBinder = binder; + } + + 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); + + AIBinder_decStrong(binder); + return ret; +} |