blob: 00678554152bb23121f6277bdfaca072a30c3a61 [file] [log] [blame]
/*
* 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();