| /* |
| * 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_auto_utils.h> |
| #include <android/binder_ibinder.h> |
| #include <gtest/gtest.h> |
| #include <nativetesthelper_jni/utils.h> |
| |
| #include <functional> |
| |
| // Helpers for testing |
| |
| template <typename T> |
| static inline ::testing::AssertionResult isOk(T) = delete; |
| |
| template <> |
| inline ::testing::AssertionResult isOk(::android::AutoAStatus t) { |
| if (AStatus_isOk(t.get())) { |
| return ::testing::AssertionSuccess(); |
| } else { |
| return ::testing::AssertionFailure(); |
| } |
| } |
| |
| template <> |
| inline ::testing::AssertionResult isOk(binder_status_t t) { |
| if (t == STATUS_OK) { |
| return ::testing::AssertionSuccess(); |
| } |
| return ::testing::AssertionFailure() << "Status: " << t; |
| } |
| |
| #define EXPECT_OK(THING) EXPECT_TRUE(isOk(THING)) |
| #define ASSERT_OK(THING) ASSERT_TRUE(isOk(THING)) |
| |
| // placeholder |
| constexpr transaction_code_t kCode = +1 + 918; |
| |
| // Usually, things at this level would be generated by the aidl compiler. This |
| // class is merely to make testing the API easier. |
| |
| struct SampleData; |
| |
| typedef std::function<void(SampleData*)> OnDestroyFunc; |
| typedef std::function<binder_status_t(transaction_code_t code, |
| const AParcel* in, AParcel* out)> |
| OnTransactFunc; |
| |
| typedef std::function<binder_status_t(AParcel*)> WriteParcel; |
| typedef std::function<binder_status_t(const AParcel*)> ReadParcel; |
| |
| static inline binder_status_t WriteNothingToParcel(AParcel*) { |
| return STATUS_OK; |
| } |
| static inline binder_status_t ReadNothingFromParcel(const AParcel*) { |
| return STATUS_OK; |
| } |
| |
| // There is an assert instances of this class are destroyed in NdkBinderTest |
| struct ThisShouldBeDestroyed { |
| static size_t numInstances(); |
| |
| ThisShouldBeDestroyed(); |
| virtual ~ThisShouldBeDestroyed(); |
| }; |
| |
| struct SampleData : ThisShouldBeDestroyed { |
| static const char* kDescriptor; |
| static const AIBinder_Class* kClass; |
| |
| static const char* kAnotherDescriptor; |
| static const AIBinder_Class* kAnotherClass; |
| |
| SampleData(const OnTransactFunc& oT = nullptr, |
| const OnDestroyFunc& oD = nullptr) |
| : onTransact(oT), onDestroy(oD) {} |
| |
| // This is called when the class is transacted on if non-null. |
| // Otherwise, STATUS_FAILED_TRANSACTION is returned. |
| OnTransactFunc onTransact; |
| |
| // This is called when the class is destroyed if non-null. |
| OnDestroyFunc onDestroy; |
| |
| // Automatically updated by this class whenever a transaction is received. |
| int numberTransactions = 0; |
| |
| __attribute__((warn_unused_result)) static AIBinder* newBinder( |
| OnTransactFunc onTransact = nullptr, OnDestroyFunc onDestroy = nullptr) { |
| SampleData* data = new SampleData(onTransact, onDestroy); |
| return AIBinder_new(kClass, static_cast<void*>(data)); |
| }; |
| |
| // Helper method to simplify transaction logic |
| static binder_status_t transact(AIBinder* binder, transaction_code_t code, |
| WriteParcel writeFunc = WriteNothingToParcel, |
| ReadParcel readFunc = ReadNothingFromParcel, |
| binder_flags_t flags = 0) { |
| AParcel* in; |
| binder_status_t status = AIBinder_prepareTransaction(binder, &in); |
| if (status != STATUS_OK) return status; |
| |
| status = writeFunc(in); |
| if (status != STATUS_OK) { |
| AParcel_delete(in); |
| return status; |
| } |
| |
| AParcel* out; |
| status = AIBinder_transact(binder, code, &in, &out, flags); |
| if (status != STATUS_OK) return status; |
| |
| status = readFunc(out); |
| AParcel_delete(out); |
| |
| return status; |
| } |
| }; |
| |
| static inline OnDestroyFunc ExpectLifetimeTransactions(size_t count) { |
| return [count](SampleData* data) { |
| EXPECT_EQ(count, data->numberTransactions) |
| << "Expected " << count |
| << " transaction(s), but over the lifetime of this object, it received " |
| << data->numberTransactions; |
| }; |
| } |
| |
| static inline OnTransactFunc TransactionsReturn(binder_status_t result) { |
| return |
| [result](transaction_code_t, const AParcel*, AParcel*) { return result; }; |
| } |
| |
| class NdkBinderTest : public ::testing::Test { |
| public: |
| void SetUp() override { instances = ThisShouldBeDestroyed::numInstances(); } |
| void TearDown() override { |
| EXPECT_EQ(instances, ThisShouldBeDestroyed::numInstances()); |
| } |
| |
| private: |
| size_t instances = 0; |
| }; |
| |
| JNIEnv* GetEnv(); |