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