summaryrefslogtreecommitdiff
path: root/libs/binder/ndk/tests/iface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/binder/ndk/tests/iface.cpp')
-rw-r--r--libs/binder/ndk/tests/iface.cpp186
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;
+}