1288 lines
41 KiB
C++
1288 lines
41 KiB
C++
/*
|
|
* Copyright (C) 2017 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.
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "hidl_test_java_native"
|
|
|
|
#include <android-base/file.h>
|
|
#include <android-base/logging.h>
|
|
|
|
#include <android/hardware/tests/baz/1.0/IBaz.h>
|
|
#include <android/hardware/tests/memory/2.0/IMemoryInterface.h>
|
|
#include <android/hardware/tests/memory/2.0/types.h>
|
|
#include <android/hardware/tests/safeunion/1.0/ISafeUnion.h>
|
|
#include <android/hidl/allocator/1.0/IAllocator.h>
|
|
#include <android/hidl/manager/1.0/IServiceManager.h>
|
|
|
|
#include <hidlmemory/mapping.h>
|
|
#include <hidl/LegacySupport.h>
|
|
#include <hidl/ServiceManagement.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <hidl/HidlTransportSupport.h>
|
|
#include <hidl/Status.h>
|
|
|
|
#include <numeric>
|
|
#include <sys/stat.h>
|
|
|
|
using ::android::sp;
|
|
using ::android::hardware::tests::baz::V1_0::IBase;
|
|
using ::android::hardware::tests::baz::V1_0::IBaz;
|
|
using ::android::hardware::tests::baz::V1_0::IBazCallback;
|
|
using ::android::hardware::tests::memory::V2_0::IMemoryInterface;
|
|
using ::android::hardware::tests::memory::V2_0::TwoMemory;
|
|
using ::android::hardware::tests::safeunion::V1_0::ISafeUnion;
|
|
|
|
using ::android::hardware::hidl_array;
|
|
using ::android::hardware::hidl_vec;
|
|
using ::android::hardware::hidl_memory;
|
|
using ::android::hardware::hidl_handle;
|
|
using ::android::hardware::hidl_string;
|
|
using ::android::hardware::defaultPassthroughServiceImplementation;
|
|
using ::android::hardware::Return;
|
|
using ::android::hardware::Status;
|
|
using ::android::hardware::Void;
|
|
|
|
using ::android::hidl::allocator::V1_0::IAllocator;
|
|
using ::android::hidl::memory::V1_0::IMemory;
|
|
|
|
using HandleTypeSafeUnion = ISafeUnion::HandleTypeSafeUnion;
|
|
using InterfaceTypeSafeUnion = ISafeUnion::InterfaceTypeSafeUnion;
|
|
using LargeSafeUnion = ISafeUnion::LargeSafeUnion;
|
|
using SmallSafeUnion = ISafeUnion::SmallSafeUnion;
|
|
|
|
struct BazCallback : public IBazCallback {
|
|
Return<void> heyItsMe(const sp<IBazCallback> &cb) override;
|
|
Return<void> hey() override;
|
|
};
|
|
|
|
Return<void> BazCallback::heyItsMe(
|
|
const sp<IBazCallback> &cb) {
|
|
LOG(INFO) << "SERVER: heyItsMe cb = " << cb.get();
|
|
|
|
return Void();
|
|
}
|
|
|
|
Return<void> BazCallback::hey() {
|
|
LOG(INFO) << "SERVER: hey";
|
|
|
|
return Void();
|
|
}
|
|
|
|
struct MemoryInterface : public IMemoryInterface {
|
|
MemoryInterface() {
|
|
sp<IAllocator> ashmem = IAllocator::getService("ashmem");
|
|
LOG_FATAL_IF(ashmem == nullptr);
|
|
ashmem->allocate(8, [&](bool success, const hidl_memory& m) {
|
|
LOG_FATAL_IF(!success);
|
|
(void) success;
|
|
mMemory = m;
|
|
});
|
|
sp<IMemory> memory = mapMemory(mMemory);
|
|
|
|
LOG_FATAL_IF(memory == nullptr);
|
|
uint8_t* data =
|
|
static_cast<uint8_t*>(static_cast<void*>(memory->getPointer()));
|
|
for (size_t i = 0; i < 8; ++i) {
|
|
data[i] = i;
|
|
}
|
|
memory->commit();
|
|
}
|
|
|
|
Return<void> bitwiseNot(const hidl_memory& mem) override {
|
|
sp<IMemory> memory = mapMemory(mem);
|
|
if (memory == nullptr) {
|
|
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
|
|
"Could not map hidl_memory");
|
|
}
|
|
uint8_t* data =
|
|
static_cast<uint8_t*>(static_cast<void*>(memory->getPointer()));
|
|
|
|
memory->update();
|
|
for (size_t i = 0; i < memory->getSize(); i++) {
|
|
data[i] = ~data[i];
|
|
}
|
|
memory->commit();
|
|
|
|
return Void();
|
|
}
|
|
|
|
Return<void> getTestMem(getTestMem_cb _hidl_cb) override {
|
|
_hidl_cb(mMemory);
|
|
return Status::ok();
|
|
}
|
|
|
|
Return<void> getSumDiff(const TwoMemory& in, getSumDiff_cb _hidl_cb) override {
|
|
if (in.mem1.size() != in.mem2.size()) {
|
|
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
|
|
"Buffers must be the same size.");
|
|
}
|
|
const size_t size = in.mem1.size();
|
|
|
|
// Map first input.
|
|
sp<IMemory> memory_in1 = mapMemory(in.mem1);
|
|
if (memory_in1 == nullptr) {
|
|
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
|
|
"Could not map hidl_memory");
|
|
}
|
|
uint8_t* data_in1 =
|
|
static_cast<uint8_t*>(static_cast<void*>(memory_in1->getPointer()));
|
|
memory_in1->update();
|
|
|
|
// Map second input.
|
|
sp<IMemory> memory_in2 = mapMemory(in.mem2);
|
|
if (memory_in2 == nullptr) {
|
|
return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
|
|
"Could not map hidl_memory");
|
|
}
|
|
uint8_t* data_in2 =
|
|
static_cast<uint8_t*>(static_cast<void*>(memory_in2->getPointer()));
|
|
memory_in2->update();
|
|
|
|
TwoMemory out;
|
|
sp<IAllocator> ashmem = IAllocator::getService("ashmem");
|
|
LOG_FATAL_IF(ashmem == nullptr);
|
|
|
|
// Map first output.
|
|
ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
|
|
LOG_FATAL_IF(!success);
|
|
(void) success;
|
|
out.mem1 = m;
|
|
});
|
|
sp<IMemory> memory_out1 = mapMemory(out.mem1);
|
|
LOG_FATAL_IF(memory_out1 == nullptr);
|
|
uint8_t* data_out1 =
|
|
static_cast<uint8_t*>(static_cast<void*>(memory_out1->getPointer()));
|
|
|
|
// Map second output.
|
|
ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
|
|
LOG_FATAL_IF(!success);
|
|
(void) success;
|
|
out.mem2 = m;
|
|
});
|
|
sp<IMemory> memory_out2 = mapMemory(out.mem2);
|
|
LOG_FATAL_IF(memory_out2 == nullptr);
|
|
uint8_t* data_out2 =
|
|
static_cast<uint8_t*>(static_cast<void*>(memory_out2->getPointer()));
|
|
|
|
for (size_t i = 0; i < size; ++i) {
|
|
data_out1[i] = data_in1[i] + data_in2[i];
|
|
data_out2[i] = data_in1[i] - data_in2[i];
|
|
}
|
|
|
|
memory_out1->commit();
|
|
memory_out2->commit();
|
|
|
|
_hidl_cb(out);
|
|
return Status::ok();
|
|
}
|
|
|
|
private:
|
|
hidl_memory mMemory;
|
|
};
|
|
|
|
using std::to_string;
|
|
|
|
static void usage(const char *me) {
|
|
fprintf(stderr, "%s [-c]lient | [-s]erver\n", me);
|
|
}
|
|
|
|
struct HidlEnvironment : public ::testing::Environment {
|
|
void SetUp() override {
|
|
}
|
|
|
|
void TearDown() override {
|
|
}
|
|
};
|
|
|
|
struct HidlTest : public ::testing::Test {
|
|
sp<IBaz> baz;
|
|
sp<ISafeUnion> safeunionInterface;
|
|
|
|
void SetUp() override {
|
|
using namespace ::android::hardware;
|
|
|
|
::android::hardware::details::waitForHwService(IBaz::descriptor, "default");
|
|
baz = IBaz::getService();
|
|
CHECK(baz != nullptr);
|
|
CHECK(baz->isRemote());
|
|
|
|
::android::hardware::details::waitForHwService(ISafeUnion::descriptor, "default");
|
|
safeunionInterface = ISafeUnion::getService();
|
|
CHECK(safeunionInterface != nullptr);
|
|
CHECK(safeunionInterface->isRemote());
|
|
}
|
|
|
|
void TearDown() override {
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
static void EXPECT_OK(const ::android::hardware::Return<T> &ret) {
|
|
EXPECT_TRUE(ret.isOk());
|
|
}
|
|
|
|
template<typename T, typename S>
|
|
static inline bool isArrayEqual(const T arr1, const S arr2, size_t size) {
|
|
for(size_t i = 0; i < size; i++)
|
|
if(arr1[i] != arr2[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
TEST_F(HidlTest, GetDescriptorTest) {
|
|
EXPECT_OK(baz->interfaceDescriptor([&] (const auto &desc) {
|
|
EXPECT_EQ(desc, IBaz::descriptor);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeBaseMethodTest) {
|
|
EXPECT_OK(baz->someBaseMethod());
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeOtherBaseMethodTest) {
|
|
IBase::Foo foo;
|
|
foo.x = 1;
|
|
foo.y.z = 2.5;
|
|
// A valid UTF-8 string
|
|
foo.y.s = "Hello, world, \x46\x6F\x6F\x20\xC2\xA9\x20\x62\x61\x72\x20\xF0\x9D\x8C\x86\x20\x54\x72\x65\x62\x6C\x65\x20\xE2\x98\x83\x20\x72\x6F\x63\x6B\x73";
|
|
|
|
foo.aaa.resize(5);
|
|
for (size_t i = 0; i < foo.aaa.size(); ++i) {
|
|
foo.aaa[i].z = 1.0f + (float)i * 0.01f;
|
|
foo.aaa[i].s = ("Hello, world " + std::to_string(i)).c_str();
|
|
}
|
|
|
|
EXPECT_OK(
|
|
baz->someOtherBaseMethod(
|
|
foo,
|
|
[&](const auto &result) {
|
|
// Strings should have the same size as they did before
|
|
// marshaling. b/35038064
|
|
EXPECT_EQ(result.y.s.size(), foo.y.s.size());
|
|
EXPECT_EQ(foo, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SomeOtherBaseMethodInvalidString) {
|
|
Return<bool> isJava = baz->isJava();
|
|
ASSERT_TRUE(isJava.isOk());
|
|
if (!isJava) {
|
|
GTEST_SKIP() << "Test only applies to Java";
|
|
}
|
|
|
|
IBase::Foo foo {
|
|
.y = {
|
|
.s = "\xff",
|
|
}
|
|
};
|
|
|
|
auto ret = baz->someOtherBaseMethod(foo, [](const IBase::Foo& ret) {
|
|
EXPECT_EQ(ret.y.s, "?"); // :)
|
|
});
|
|
|
|
EXPECT_TRUE(ret.isOk());
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeMethodWithFooArraysTest) {
|
|
hidl_array<IBase::Foo, 2> foo;
|
|
|
|
foo[0].x = 1;
|
|
foo[0].y.z = 2.5;
|
|
foo[0].y.s = "Hello, world";
|
|
|
|
foo[0].aaa.resize(5);
|
|
for (size_t i = 0; i < foo[0].aaa.size(); ++i) {
|
|
foo[0].aaa[i].z = 1.0f + (float)i * 0.01f;
|
|
foo[0].aaa[i].s = ("Hello, world " + std::to_string(i)).c_str();
|
|
}
|
|
|
|
foo[1].x = 2;
|
|
foo[1].y.z = -2.5;
|
|
foo[1].y.s = "Morituri te salutant";
|
|
|
|
foo[1].aaa.resize(3);
|
|
for (size_t i = 0; i < foo[1].aaa.size(); ++i) {
|
|
foo[1].aaa[i].z = 2.0f - (float)i * 0.01f;
|
|
foo[1].aaa[i].s = ("Alea iacta est: " + std::to_string(i)).c_str();
|
|
}
|
|
|
|
hidl_array<IBaz::Foo, 2> fooExpectedOutput;
|
|
fooExpectedOutput[0] = foo[1];
|
|
fooExpectedOutput[1] = foo[0];
|
|
|
|
EXPECT_OK(
|
|
baz->someMethodWithFooArrays(
|
|
foo,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(result, fooExpectedOutput);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeMethodWithFooVectorsTest) {
|
|
hidl_vec<IBase::Foo> foo;
|
|
foo.resize(2);
|
|
|
|
foo[0].x = 1;
|
|
foo[0].y.z = 2.5;
|
|
foo[0].y.s = "Hello, world";
|
|
|
|
foo[0].aaa.resize(5);
|
|
for (size_t i = 0; i < foo[0].aaa.size(); ++i) {
|
|
foo[0].aaa[i].z = 1.0f + (float)i * 0.01f;
|
|
foo[0].aaa[i].s = ("Hello, world " + std::to_string(i)).c_str();
|
|
}
|
|
|
|
foo[1].x = 2;
|
|
foo[1].y.z = -2.5;
|
|
foo[1].y.s = "Morituri te salutant";
|
|
|
|
foo[1].aaa.resize(3);
|
|
for (size_t i = 0; i < foo[1].aaa.size(); ++i) {
|
|
foo[1].aaa[i].z = 2.0f - (float)i * 0.01f;
|
|
foo[1].aaa[i].s = ("Alea iacta est: " + std::to_string(i)).c_str();
|
|
}
|
|
|
|
hidl_vec<IBaz::Foo> fooExpectedOutput;
|
|
fooExpectedOutput.resize(2);
|
|
fooExpectedOutput[0] = foo[1];
|
|
fooExpectedOutput[1] = foo[0];
|
|
|
|
EXPECT_OK(
|
|
baz->someMethodWithFooVectors(
|
|
foo,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(result, fooExpectedOutput);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeMethodWithVectorOfArray) {
|
|
IBase::VectorOfArray in, expectedOut;
|
|
in.addresses.resize(3);
|
|
expectedOut.addresses.resize(3);
|
|
|
|
size_t k = 0;
|
|
const size_t n = in.addresses.size();
|
|
|
|
for (size_t i = 0; i < n; ++i) {
|
|
for (size_t j = 0; j < 6; ++j, ++k) {
|
|
in.addresses[i][j] = k;
|
|
expectedOut.addresses[n - 1 - i][j] = k;
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(
|
|
baz->someMethodWithVectorOfArray(
|
|
in,
|
|
[&](const auto &out) {
|
|
EXPECT_EQ(expectedOut, out);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeMethodTakingAVectorOfArray) {
|
|
hidl_vec<hidl_array<uint8_t, 6> > in, expectedOut;
|
|
in.resize(3);
|
|
expectedOut.resize(3);
|
|
|
|
size_t k = 0;
|
|
const size_t n = in.size();
|
|
for (size_t i = 0; i < n; ++i) {
|
|
for (size_t j = 0; j < 6; ++j, ++k) {
|
|
in[i][j] = k;
|
|
expectedOut[n - 1 - i][j] = k;
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(
|
|
baz->someMethodTakingAVectorOfArray(
|
|
in,
|
|
[&](const auto &out) {
|
|
EXPECT_EQ(expectedOut, out);
|
|
}));
|
|
}
|
|
|
|
static std::string numberToEnglish(int x) {
|
|
static const char *const kDigits[] = {
|
|
"zero",
|
|
"one",
|
|
"two",
|
|
"three",
|
|
"four",
|
|
"five",
|
|
"six",
|
|
"seven",
|
|
"eight",
|
|
"nine",
|
|
};
|
|
|
|
if (x < 0) {
|
|
return "negative " + numberToEnglish(-x);
|
|
}
|
|
|
|
if (x < 10) {
|
|
return kDigits[x];
|
|
}
|
|
|
|
if (x <= 15) {
|
|
static const char *const kSpecialTens[] = {
|
|
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
|
|
};
|
|
|
|
return kSpecialTens[x - 10];
|
|
}
|
|
|
|
if (x < 20) {
|
|
return std::string(kDigits[x % 10]) + "teen";
|
|
}
|
|
|
|
if (x < 100) {
|
|
static const char *const kDecades[] = {
|
|
"twenty", "thirty", "forty", "fifty", "sixty", "seventy",
|
|
"eighty", "ninety",
|
|
};
|
|
|
|
return std::string(kDecades[x / 10 - 2]) + kDigits[x % 10];
|
|
}
|
|
|
|
return "positively huge!";
|
|
}
|
|
|
|
TEST_F(HidlTest, BazTransposeTest) {
|
|
IBase::StringMatrix5x3 in;
|
|
IBase::StringMatrix3x5 expectedOut;
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
in.s[i][j] = expectedOut.s[j][i] = numberToEnglish(3 * i + j + 1).c_str();
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(baz->transpose(
|
|
in,
|
|
[&](const auto &out) {
|
|
EXPECT_EQ(expectedOut, out);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazTranspose2Test) {
|
|
hidl_array<hidl_string, 5, 3> in;
|
|
hidl_array<hidl_string, 3, 5> expectedOut;
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
for (int j = 0; j < 3; ++j) {
|
|
in[i][j] = expectedOut[j][i] = numberToEnglish(3 * i + j + 1).c_str();
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(baz->transpose2(
|
|
in,
|
|
[&](const auto &out) {
|
|
EXPECT_EQ(expectedOut, out);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeBoolMethodTest) {
|
|
auto result = baz->someBoolMethod(true);
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(result, false);
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeBoolArrayMethodTest) {
|
|
hidl_array<bool, 3> someBoolArray;
|
|
someBoolArray[0] = true;
|
|
someBoolArray[1] = false;
|
|
someBoolArray[2] = true;
|
|
|
|
hidl_array<bool, 4> expectedOut;
|
|
expectedOut[0] = false;
|
|
expectedOut[1] = true;
|
|
expectedOut[2] = false;
|
|
expectedOut[3] = true;
|
|
|
|
EXPECT_OK(
|
|
baz->someBoolArrayMethod(
|
|
someBoolArray,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expectedOut, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazSomeBoolVectorMethodTest) {
|
|
hidl_vec<bool> someBoolVector, expected;
|
|
someBoolVector.resize(4);
|
|
expected.resize(4);
|
|
|
|
for (size_t i = 0; i < someBoolVector.size(); ++i) {
|
|
someBoolVector[i] = ((i & 1) == 0);
|
|
expected[i] = !someBoolVector[i];
|
|
}
|
|
|
|
EXPECT_OK(
|
|
baz->someBoolVectorMethod(
|
|
someBoolVector,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expected, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazDoThisMethodTest) {
|
|
EXPECT_OK(baz->doThis(1.0f));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazDoThatAndReturnSomethingMethodTest) {
|
|
auto result = baz->doThatAndReturnSomething(1);
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(result, 666);
|
|
}
|
|
|
|
TEST_F(HidlTest, BazDoQuiteABitMethodTest) {
|
|
auto result = baz->doQuiteABit(1, 2LL, 3.0f, 4.0);
|
|
|
|
EXPECT_OK(result);
|
|
EXPECT_EQ(result, 666.5);
|
|
}
|
|
|
|
TEST_F(HidlTest, BazDoSomethingElseMethodTest) {
|
|
hidl_array<int32_t, 15> param;
|
|
hidl_array<int32_t, 32> expected;
|
|
|
|
for (size_t i = 0; i < 15; ++i) {
|
|
param[i] = expected[15 + i] = i;
|
|
expected[i] = 2 * i;
|
|
}
|
|
|
|
expected[30] = 1;
|
|
expected[31] = 2;
|
|
|
|
EXPECT_OK(
|
|
baz->doSomethingElse(
|
|
param,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expected, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazDoStuffAndReturnAStringMethodTest) {
|
|
std::string expected = "Hello, world!";
|
|
EXPECT_OK(
|
|
baz->doStuffAndReturnAString(
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expected, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazMapThisVectorMethodTest) {
|
|
hidl_vec<int32_t> vec_param, expected;
|
|
vec_param.resize(15);
|
|
expected.resize(15);
|
|
|
|
for (size_t i = 0; i < 15; ++i) {
|
|
vec_param[i] = i;
|
|
expected[i] = 2 * i;
|
|
}
|
|
|
|
EXPECT_OK(
|
|
baz->mapThisVector(
|
|
vec_param,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expected, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazCallMeMethodTest) {
|
|
EXPECT_OK(baz->callMe(new BazCallback()));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazCallMeLaterMethodTest) {
|
|
EXPECT_OK(baz->callMeLater(new BazCallback()));
|
|
EXPECT_OK(baz->iAmFreeNow());
|
|
}
|
|
|
|
TEST_F(HidlTest, BazUseAnEnumMethodTest) {
|
|
auto result = baz->useAnEnum(IBaz::SomeEnum::bar);
|
|
|
|
EXPECT_OK(result);
|
|
EXPECT_TRUE(result == IBaz::SomeEnum::quux);
|
|
}
|
|
|
|
TEST_F(HidlTest, BazHaveSomeStringsMethodTest) {
|
|
hidl_array<hidl_string, 3> string_params;
|
|
string_params[0] = "one";
|
|
string_params[1] = "two";
|
|
string_params[2] = "three";
|
|
|
|
hidl_array<hidl_string, 2> expected;
|
|
expected[0] = "Hello";
|
|
expected[1] = "World";
|
|
|
|
EXPECT_OK(
|
|
baz->haveSomeStrings(
|
|
string_params,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expected, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazHaveAStringVecMethodTest) {
|
|
hidl_vec<hidl_string> string_vec{ "Uno", "Dos", "Tres", "Cuatro" };
|
|
hidl_vec<hidl_string> expected{"Hello", "World"};
|
|
|
|
EXPECT_OK(
|
|
baz->haveAStringVec(
|
|
string_vec,
|
|
[&](const auto &result) {
|
|
EXPECT_EQ(expected, result);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazRepeatBitfieldVecTest) {
|
|
hidl_vec<uint8_t> vec{0 | IBaz::BitField::V1, 0 | IBaz::BitField::V2};
|
|
|
|
EXPECT_OK(baz->repeatBitfieldVec(vec, [&](const auto& result) { EXPECT_EQ(vec, result); }));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazReturnABunchOfStringsMethodTest) {
|
|
std::string expectedA = "Eins";
|
|
std::string expectedB = "Zwei";
|
|
std::string expectedC = "Drei";
|
|
EXPECT_OK(
|
|
baz->returnABunchOfStrings(
|
|
[&](const auto &a, const auto &b, const auto &c) {
|
|
EXPECT_EQ(a, expectedA);
|
|
EXPECT_EQ(b, expectedB);
|
|
EXPECT_EQ(c, expectedC);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazTestArrays) {
|
|
IBase::LotsOfPrimitiveArrays in;
|
|
|
|
for (size_t i = 0; i < 128; ++i) {
|
|
in.byte1[i] = i;
|
|
in.boolean1[i] = (i & 4) != 0;
|
|
in.double1[i] = i;
|
|
}
|
|
|
|
size_t k = 0;
|
|
for (size_t i = 0; i < 8; ++i) {
|
|
for (size_t j = 0; j < 128; ++j, ++k) {
|
|
in.byte2[i][j] = k;
|
|
in.boolean2[i][j] = (k & 4) != 0;
|
|
in.double2[i][j] = k;
|
|
}
|
|
}
|
|
|
|
size_t m = 0;
|
|
for (size_t i = 0; i < 8; ++i) {
|
|
for (size_t j = 0; j < 16; ++j) {
|
|
for (size_t k = 0; k < 128; ++k, ++m) {
|
|
in.byte3[i][j][k] = m;
|
|
in.boolean3[i][j][k] = (m & 4) != 0;
|
|
in.double3[i][j][k] = m;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(
|
|
baz->testArrays(in,
|
|
[&](const auto &out) {
|
|
EXPECT_EQ(in, out);
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazTestByteVecs) {
|
|
hidl_vec<IBase::ByteOneDim> in;
|
|
in.resize(8);
|
|
|
|
size_t k = 0;
|
|
for (size_t i = 0; i < in.size(); ++i) {
|
|
for (size_t j = 0; j < 128; ++j, ++k) {
|
|
in[i][j] = k;
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(baz->testByteVecs(
|
|
in, [&](const auto &out) { EXPECT_EQ(in, out); }));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazTestBooleanVecs) {
|
|
hidl_vec<IBase::BooleanOneDim> in;
|
|
in.resize(8);
|
|
|
|
size_t k = 0;
|
|
for (size_t i = 0; i < in.size(); ++i) {
|
|
for (size_t j = 0; j < 128; ++j, ++k) {
|
|
in[i][j] = (k & 4) != 0;
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(baz->testBooleanVecs(
|
|
in, [&](const auto &out) { EXPECT_EQ(in, out); }));
|
|
}
|
|
|
|
TEST_F(HidlTest, BazTestDoubleVecs) {
|
|
hidl_vec<IBase::DoubleOneDim> in;
|
|
in.resize(8);
|
|
|
|
size_t k = 0;
|
|
for (size_t i = 0; i < in.size(); ++i) {
|
|
for (size_t j = 0; j < 128; ++j, ++k) {
|
|
in[i][j] = k;
|
|
}
|
|
}
|
|
|
|
EXPECT_OK(baz->testDoubleVecs(
|
|
in, [&](const auto &out) { EXPECT_EQ(in, out); }));
|
|
}
|
|
|
|
TEST_F(HidlTest, TwowayMethodOnewayEnabledTest) {
|
|
using ::android::hardware::IBinder;
|
|
using ::android::hardware::Parcel;
|
|
|
|
sp<IBinder> binder = ::android::hardware::toBinder(baz);
|
|
|
|
Parcel request, reply;
|
|
EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBaz::descriptor));
|
|
EXPECT_EQ(::android::OK, request.writeInt64(1234));
|
|
// IBaz::doThatAndReturnSomething is two-way but we call it using FLAG_ONEWAY.
|
|
EXPECT_EQ(::android::OK, binder->transact(19 /*doThatAndReturnSomething*/, request, &reply,
|
|
IBinder::FLAG_ONEWAY));
|
|
|
|
::android::hardware::Status status;
|
|
EXPECT_EQ(::android::NOT_ENOUGH_DATA, ::android::hardware::readFromParcel(&status, reply));
|
|
EXPECT_EQ(::android::hardware::Status::EX_TRANSACTION_FAILED, status.exceptionCode());
|
|
|
|
EXPECT_OK(baz->ping()); // still works
|
|
}
|
|
|
|
TEST_F(HidlTest, OnewayMethodOnewayDisabledTest) {
|
|
Return<bool> isJava = baz->isJava();
|
|
ASSERT_TRUE(isJava.isOk());
|
|
|
|
using ::android::hardware::IBinder;
|
|
using ::android::hardware::Parcel;
|
|
|
|
sp<IBinder> binder = ::android::hardware::toBinder(baz);
|
|
|
|
Parcel request, reply;
|
|
EXPECT_EQ(::android::OK, request.writeInterfaceToken(IBaz::descriptor));
|
|
EXPECT_EQ(::android::OK, request.writeFloat(1.0f));
|
|
// IBaz::doThis is oneway but we call it without using FLAG_ONEWAY.
|
|
EXPECT_EQ(
|
|
// Expect UNKNOWN_ERROR because the JNI class JHwBinder always sets
|
|
// the reply to UNKNOWN_ERROR for two-way transactions if the
|
|
// transaction itself did not send a reply.
|
|
//
|
|
// C++ does not specifically check this error case.
|
|
(isJava ? ::android::UNKNOWN_ERROR : 0),
|
|
binder->transact(18 /*doThis*/, request, &reply, 0 /* Not FLAG_ONEWAY */));
|
|
|
|
EXPECT_OK(baz->ping()); // still works
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionNoInitTest) {
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::noinit, safeUnion.getDiscriminator());
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionSimpleTest) {
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_OK(safeunionInterface->setA(safeUnion, -5, [&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::a, safeUnion.getDiscriminator());
|
|
EXPECT_EQ(-5, safeUnion.a());
|
|
|
|
uint64_t max = std::numeric_limits<uint64_t>::max();
|
|
EXPECT_OK(
|
|
safeunionInterface->setD(safeUnion, max, [&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::d, safeUnion.getDiscriminator());
|
|
EXPECT_EQ(max, safeUnion.d());
|
|
}));
|
|
}));
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionArrayLikeTypesTest) {
|
|
const std::array<int64_t, 5> testArray{1, -2, 3, -4, 5};
|
|
const hidl_vec<uint64_t> testVector{std::numeric_limits<uint64_t>::max()};
|
|
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_OK(
|
|
safeunionInterface->setF(safeUnion, testArray, [&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::f, safeUnion.getDiscriminator());
|
|
|
|
for (size_t i = 0; i < testArray.size(); i++) {
|
|
EXPECT_EQ(testArray[i], safeUnion.f()[i]);
|
|
}
|
|
}));
|
|
|
|
EXPECT_OK(
|
|
safeunionInterface->setI(safeUnion, testVector, [&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::i, safeUnion.getDiscriminator());
|
|
EXPECT_EQ(testVector, safeUnion.i());
|
|
}));
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionStringTypeTest) {
|
|
const std::string testString =
|
|
"This is an inordinately long test string to exercise hidl_string types in safe unions.";
|
|
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_OK(safeunionInterface->setG(
|
|
safeUnion, hidl_string(testString), [&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::g, safeUnion.getDiscriminator());
|
|
EXPECT_EQ(testString, std::string(safeUnion.g()));
|
|
}));
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionNestedTest) {
|
|
SmallSafeUnion smallSafeUnion;
|
|
smallSafeUnion.a(1);
|
|
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_OK(safeunionInterface->setL(
|
|
safeUnion, smallSafeUnion, [&](const LargeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(LargeSafeUnion::hidl_discriminator::l, safeUnion.getDiscriminator());
|
|
|
|
EXPECT_EQ(SmallSafeUnion::hidl_discriminator::a, safeUnion.l().getDiscriminator());
|
|
EXPECT_EQ(1, safeUnion.l().a());
|
|
}));
|
|
}));
|
|
}
|
|
|
|
// does not check for fd equality
|
|
static void checkNativeHandlesDataEquality(const native_handle_t* reference,
|
|
const native_handle_t* result) {
|
|
if (reference == nullptr || result == nullptr) {
|
|
EXPECT_EQ(reference == nullptr, result == nullptr);
|
|
return;
|
|
}
|
|
|
|
ASSERT_NE(reference, result);
|
|
ASSERT_EQ(reference->version, result->version);
|
|
EXPECT_EQ(reference->numFds, result->numFds);
|
|
EXPECT_EQ(reference->numInts, result->numInts);
|
|
|
|
int offset = reference->numFds;
|
|
int numInts = reference->numInts;
|
|
EXPECT_TRUE(isArrayEqual(&(reference->data[offset]), &(result->data[offset]), numInts));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionInterfaceNullHandleTest) {
|
|
InterfaceTypeSafeUnion safeUnion;
|
|
|
|
EXPECT_OK(safeunionInterface->setInterfaceF(
|
|
safeUnion, hidl_handle(nullptr), [&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::f,
|
|
safeUnion.getDiscriminator());
|
|
|
|
checkNativeHandlesDataEquality(nullptr, safeUnion.f().getNativeHandle());
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionInterfaceTest) {
|
|
const std::array<int8_t, 7> testArray{-1, -2, -3, 0, 1, 2, 3};
|
|
const hidl_vec<hidl_string> testVector{"So", "Many", "Words"};
|
|
const std::string testStringA = "Hello";
|
|
const std::string testStringB = "World";
|
|
|
|
const std::array<int, 6> testHandleData{2, -32, 10, -4329454, 11, 24};
|
|
native_handle_t* h = native_handle_create(0, testHandleData.size());
|
|
CHECK(sizeof(testHandleData) == testHandleData.size() * sizeof(int));
|
|
std::memcpy(h->data, testHandleData.data(), sizeof(testHandleData));
|
|
|
|
std::vector<hidl_handle> testHandlesVector(256);
|
|
for (size_t i = 0; i < testHandlesVector.size(); i++) {
|
|
testHandlesVector[i].setTo(native_handle_clone(h), true /* shouldOwn */);
|
|
}
|
|
|
|
EXPECT_OK(
|
|
safeunionInterface->newInterfaceTypeSafeUnion([&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::noinit,
|
|
safeUnion.getDiscriminator());
|
|
|
|
EXPECT_OK(safeunionInterface->setInterfaceB(
|
|
safeUnion, testArray, [&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::b,
|
|
safeUnion.getDiscriminator());
|
|
|
|
for (size_t i = 0; i < testArray.size(); i++) {
|
|
EXPECT_EQ(testArray[i], safeUnion.b()[i]);
|
|
}
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setInterfaceD(
|
|
safeUnion, testStringA, [&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::d,
|
|
safeUnion.getDiscriminator());
|
|
EXPECT_EQ(testStringA, safeUnion.d());
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setInterfaceE(
|
|
safeUnion, testVector, [&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::e,
|
|
safeUnion.getDiscriminator());
|
|
EXPECT_EQ(testVector, safeUnion.e());
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setInterfaceF(
|
|
safeUnion, hidl_handle(h), [&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::f,
|
|
safeUnion.getDiscriminator());
|
|
|
|
const native_handle_t* result = safeUnion.f().getNativeHandle();
|
|
checkNativeHandlesDataEquality(h, result);
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setInterfaceG(
|
|
safeUnion, testHandlesVector, [&](const InterfaceTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::g,
|
|
safeUnion.getDiscriminator());
|
|
|
|
for (size_t i = 0; i < testHandlesVector.size(); i++) {
|
|
checkNativeHandlesDataEquality(h, safeUnion.g()[i].getNativeHandle());
|
|
}
|
|
}));
|
|
}));
|
|
|
|
using android::hardware::defaultServiceManager;
|
|
using android::hardware::interfacesEqual;
|
|
|
|
InterfaceTypeSafeUnion safeUnion;
|
|
safeUnion.c(defaultServiceManager());
|
|
|
|
EXPECT_EQ(InterfaceTypeSafeUnion::hidl_discriminator::c, safeUnion.getDiscriminator());
|
|
EXPECT_TRUE(interfacesEqual(safeUnion.c(), defaultServiceManager()));
|
|
|
|
native_handle_delete(h);
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionNullHandleTest) {
|
|
HandleTypeSafeUnion safeUnion;
|
|
|
|
EXPECT_OK(safeunionInterface->setHandleA(
|
|
safeUnion, hidl_handle(nullptr), [&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
|
|
safeUnion.getDiscriminator());
|
|
|
|
checkNativeHandlesDataEquality(nullptr, safeUnion.a().getNativeHandle());
|
|
}));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionSimpleHandleTest) {
|
|
const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
|
|
native_handle_t* h = native_handle_create(0, testData.size());
|
|
ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
|
|
std::memcpy(h->data, testData.data(), sizeof(testData));
|
|
|
|
std::array<hidl_handle, 5> testArray;
|
|
for (size_t i = 0; i < testArray.size(); i++) {
|
|
testArray[i].setTo(native_handle_clone(h), true /* shouldOwn */);
|
|
}
|
|
|
|
std::vector<hidl_handle> testVector(256);
|
|
for (size_t i = 0; i < testVector.size(); i++) {
|
|
testVector[i].setTo(native_handle_clone(h), true /* shouldOwn */);
|
|
}
|
|
|
|
EXPECT_OK(
|
|
safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_OK(safeunionInterface->setHandleA(
|
|
safeUnion, hidl_handle(h), [&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
|
|
safeUnion.getDiscriminator());
|
|
|
|
checkNativeHandlesDataEquality(h, safeUnion.a().getNativeHandle());
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setHandleB(
|
|
safeUnion, testArray, [&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::b,
|
|
safeUnion.getDiscriminator());
|
|
|
|
for (size_t i = 0; i < testArray.size(); i++) {
|
|
checkNativeHandlesDataEquality(h, safeUnion.b()[i].getNativeHandle());
|
|
}
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setHandleC(
|
|
safeUnion, testVector, [&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::c,
|
|
safeUnion.getDiscriminator());
|
|
|
|
for (size_t i = 0; i < testVector.size(); i++) {
|
|
checkNativeHandlesDataEquality(h, safeUnion.c()[i].getNativeHandle());
|
|
}
|
|
}));
|
|
}));
|
|
|
|
native_handle_delete(h);
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionVecOfHandlesWithOneFdTest) {
|
|
const std::vector<std::string> testStrings{"This ", "is ", "so ", "much ", "data!\n"};
|
|
const std::string testFileName = "/data/local/tmp/SafeUnionVecOfHandlesWithOneFdTest";
|
|
const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
|
|
ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
|
|
|
|
const std::string goldenResult = std::accumulate(testStrings.begin(),
|
|
testStrings.end(),
|
|
std::string());
|
|
|
|
int fd = open(testFileName.c_str(), (O_RDWR | O_TRUNC | O_CREAT), (S_IRUSR | S_IWUSR));
|
|
ASSERT_TRUE(fd >= 0);
|
|
|
|
native_handle* h = native_handle_create(1 /* numFds */, testData.size() /* numInts */);
|
|
std::memcpy(&(h->data[1]), testData.data(), sizeof(testData));
|
|
h->data[0] = fd;
|
|
|
|
hidl_vec<hidl_handle> testHandles(testStrings.size());
|
|
for (size_t i = 0; i < testHandles.size(); i++) {
|
|
testHandles[i].setTo(native_handle_clone(h), true /* shouldOwn */);
|
|
}
|
|
|
|
EXPECT_OK(
|
|
safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_OK(safeunionInterface->setHandleC(
|
|
safeUnion, testHandles, [&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::c,
|
|
safeUnion.getDiscriminator());
|
|
|
|
for (size_t i = 0; i < safeUnion.c().size(); i++) {
|
|
const native_handle_t* reference = testHandles[i].getNativeHandle();
|
|
const native_handle_t* result = safeUnion.c()[i].getNativeHandle();
|
|
checkNativeHandlesDataEquality(reference, result);
|
|
|
|
// Original FDs should be dup'd
|
|
int resultFd = result->data[0];
|
|
EXPECT_NE(reference->data[0], resultFd);
|
|
|
|
EXPECT_TRUE(android::base::WriteStringToFd(testStrings[i], resultFd));
|
|
EXPECT_EQ(0, fsync(resultFd));
|
|
}
|
|
}));
|
|
}));
|
|
|
|
std::string result;
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
EXPECT_TRUE(android::base::ReadFdToString(fd, &result));
|
|
EXPECT_EQ(goldenResult, result);
|
|
|
|
native_handle_delete(h);
|
|
EXPECT_EQ(0, close(fd));
|
|
EXPECT_EQ(0, remove(testFileName.c_str()));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionHandleWithMultipleFdsTest) {
|
|
const std::vector<std::string> testStrings{"This ", "is ", "so ", "much ", "data!\n"};
|
|
const std::string testFileName = "/data/local/tmp/SafeUnionHandleWithMultipleFdsTest";
|
|
const std::array<int, 6> testData{2, -32, 10, -4329454, 11, 24};
|
|
ASSERT_EQ(sizeof(testData), testData.size() * sizeof(int));
|
|
|
|
const std::string goldenResult = std::accumulate(testStrings.begin(),
|
|
testStrings.end(),
|
|
std::string());
|
|
|
|
int fd = open(testFileName.c_str(), (O_RDWR | O_TRUNC | O_CREAT), (S_IRUSR | S_IWUSR));
|
|
ASSERT_TRUE(fd >= 0);
|
|
|
|
const int numFds = testStrings.size();
|
|
native_handle* h = native_handle_create(numFds, testData.size() /* numInts */);
|
|
std::memcpy(&(h->data[numFds]), testData.data(), sizeof(testData));
|
|
for (size_t i = 0; i < numFds; i++) {
|
|
h->data[i] = fd;
|
|
}
|
|
|
|
hidl_handle testHandle;
|
|
testHandle.setTo(h, false /* shouldOwn */);
|
|
|
|
EXPECT_OK(
|
|
safeunionInterface->newHandleTypeSafeUnion([&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_OK(safeunionInterface->setHandleA(
|
|
safeUnion, testHandle, [&](const HandleTypeSafeUnion& safeUnion) {
|
|
EXPECT_EQ(HandleTypeSafeUnion::hidl_discriminator::a,
|
|
safeUnion.getDiscriminator());
|
|
|
|
const native_handle_t* result = safeUnion.a().getNativeHandle();
|
|
checkNativeHandlesDataEquality(h, result);
|
|
|
|
for (size_t i = 0; i < result->numFds; i++) {
|
|
// Original FDs should be dup'd
|
|
int resultFd = result->data[i];
|
|
EXPECT_NE(h->data[i], resultFd);
|
|
|
|
EXPECT_TRUE(android::base::WriteStringToFd(testStrings[i], resultFd));
|
|
EXPECT_EQ(0, fsync(resultFd));
|
|
}
|
|
}));
|
|
}));
|
|
|
|
std::string result;
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
EXPECT_TRUE(android::base::ReadFdToString(fd, &result));
|
|
EXPECT_EQ(goldenResult, result);
|
|
|
|
native_handle_delete(h);
|
|
EXPECT_EQ(0, close(fd));
|
|
EXPECT_EQ(0, remove(testFileName.c_str()));
|
|
}
|
|
|
|
TEST_F(HidlTest, SafeUnionEqualityTest) {
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& one) {
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
|
|
EXPECT_TRUE(one == two);
|
|
EXPECT_FALSE(one != two);
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->setA(one, 1, [&](const LargeSafeUnion& one) {
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
|
|
EXPECT_FALSE(one == two);
|
|
EXPECT_TRUE(one != two);
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
|
|
EXPECT_OK(safeunionInterface->setB(two, 1, [&](const LargeSafeUnion& two) {
|
|
EXPECT_FALSE(one == two);
|
|
EXPECT_TRUE(one != two);
|
|
}));
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
|
|
EXPECT_OK(safeunionInterface->setA(two, 2, [&](const LargeSafeUnion& two) {
|
|
EXPECT_FALSE(one == two);
|
|
EXPECT_TRUE(one != two);
|
|
}));
|
|
}));
|
|
|
|
EXPECT_OK(safeunionInterface->newLargeSafeUnion([&](const LargeSafeUnion& two) {
|
|
EXPECT_OK(safeunionInterface->setA(two, 1, [&](const LargeSafeUnion& two) {
|
|
EXPECT_TRUE(one == two);
|
|
EXPECT_FALSE(one != two);
|
|
}));
|
|
}));
|
|
}));
|
|
}));
|
|
}
|
|
|
|
template <typename T, size_t start, size_t end>
|
|
void expectRangeEqual(const T* t, uint8_t byte) {
|
|
static_assert(start < sizeof(T));
|
|
static_assert(end <= sizeof(T));
|
|
|
|
const uint8_t* buf = reinterpret_cast<const uint8_t*>(t);
|
|
|
|
for (size_t i = start; i < end; i++) {
|
|
EXPECT_EQ(byte, buf[i]) << i;
|
|
}
|
|
}
|
|
|
|
TEST_F(HidlTest, UninitTest) {
|
|
Return<bool> isJava = baz->isJava();
|
|
ASSERT_TRUE(isJava.isOk());
|
|
if (!isJava) {
|
|
GTEST_SKIP() << "Test only applies to Java";
|
|
}
|
|
|
|
IBase::Foo foo;
|
|
foo.x = 1;
|
|
foo.y = {0, ""};
|
|
|
|
static_assert(offsetof(IBase::Foo, x) == 0);
|
|
static_assert(sizeof(foo.x) == 4);
|
|
static_assert(offsetof(IBase::Foo, aaa) == 8);
|
|
|
|
uint8_t* buf = reinterpret_cast<uint8_t*>(&foo);
|
|
memset(buf + 4, 0xFF, 4);
|
|
|
|
// this should not affect the result for remote Java (but would for remote C++)
|
|
expectRangeEqual<IBase::Foo, 4, 8>(&foo, 0xFF);
|
|
|
|
// run many times, if this error case is hit, it will only be hit
|
|
// sometimes.
|
|
for (size_t i = 0; i < 100; i++) {
|
|
EXPECT_OK(baz->someOtherBaseMethod(
|
|
foo, [](const IBase::Foo& foo) { expectRangeEqual<IBase::Foo, 4, 8>(&foo, 0); }));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
using namespace android::hardware;
|
|
details::setTrebleTestingOverride(true);
|
|
|
|
const char *me = argv[0];
|
|
|
|
bool wantClient = false;
|
|
bool wantServer = false;
|
|
|
|
int res;
|
|
while ((res = getopt(argc, argv, "chs")) >= 0) {
|
|
switch (res) {
|
|
case 'c':
|
|
{
|
|
wantClient = true;
|
|
break;
|
|
}
|
|
|
|
case 's':
|
|
{
|
|
wantServer = true;
|
|
break;
|
|
}
|
|
|
|
case '?':
|
|
case 'h':
|
|
default:
|
|
{
|
|
usage(me);
|
|
exit(1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((!wantClient && !wantServer) || (wantClient && wantServer)) {
|
|
usage(me);
|
|
exit(1);
|
|
}
|
|
|
|
if (wantClient) {
|
|
::testing::AddGlobalTestEnvironment(new HidlEnvironment);
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
int status = RUN_ALL_TESTS();
|
|
return status;
|
|
}
|
|
|
|
::android::status_t status;
|
|
configureRpcThreadpool(1, true);
|
|
|
|
status = registerPassthroughServiceImplementation<IBaz>();
|
|
CHECK(status == ::android::OK) << "IBaz didn't register";
|
|
|
|
status = registerPassthroughServiceImplementation<ISafeUnion>();
|
|
CHECK(status == ::android::OK) << "ISafeUnion didn't register";
|
|
|
|
sp<IMemoryInterface> memoryInterface = new MemoryInterface();
|
|
status = memoryInterface->registerAsService();
|
|
CHECK(status == ::android::OK) << "IMemoryInterface didn't register";
|
|
|
|
joinRpcThreadpool();
|
|
return 0;
|
|
}
|