Merge changes from topic "java_native_handles"
* changes:
Testing native handles with non-zero FDs
Augmenting hidl-gen to support native handles in Java
diff --git a/CompoundType.cpp b/CompoundType.cpp
index 54baa84..c2a0f34 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -1829,18 +1829,7 @@
out.indent(2);
- bool useName = false;
- for (const auto &field : *mFields) {
- if (field->type().useNameInEmitReaderWriterEmbedded(isReader)) {
- useName = true;
- break;
- }
- }
- std::string name = useName ? "obj" : "/* obj */";
- // if not useName, then obj should not be used at all,
- // then the #error should not be emitted.
- std::string error = useName ? "" : "\n#error\n";
-
+ const std::string name = "obj";
if (isReader) {
out << "const " << space << localName() << " &" << name << ",\n";
out << "const ::android::hardware::Parcel &parcel,\n";
@@ -1876,8 +1865,8 @@
}
const std::string fieldName = (mStyle == STYLE_SAFE_UNION)
- ? (name + "." + field->name() + "()" + error)
- : (name + "." + field->name() + error);
+ ? (name + "." + field->name() + "()")
+ : (name + "." + field->name());
const std::string fieldOffset = (mStyle == STYLE_SAFE_UNION)
? (name + ".hidl_getUnionOffset() " +
diff --git a/HandleType.cpp b/HandleType.cpp
index 7b6545d..56660a6 100644
--- a/HandleType.cpp
+++ b/HandleType.cpp
@@ -51,6 +51,14 @@
}
}
+std::string HandleType::getJavaType(bool /* forInitializer */) const {
+ return "android.os.NativeHandle";
+}
+
+std::string HandleType::getJavaSuffix() const {
+ return "NativeHandle";
+}
+
std::string HandleType::getVtsType() const {
return "TYPE_HANDLE";
}
@@ -89,15 +97,11 @@
}
}
-bool HandleType::useNameInEmitReaderWriterEmbedded(bool isReader) const {
- return !isReader;
-}
-
void HandleType::emitReaderWriterEmbedded(
Formatter &out,
size_t /* depth */,
const std::string &name,
- const std::string &sanitizedName,
+ const std::string & /* sanitizedName */,
bool nameIsPointer,
const std::string &parcelObj,
bool parcelObjIsPointer,
@@ -105,52 +109,65 @@
ErrorMode mode,
const std::string &parentName,
const std::string &offsetText) const {
+ emitReaderWriterEmbeddedForTypeName(
+ out,
+ name,
+ nameIsPointer,
+ parcelObj,
+ parcelObjIsPointer,
+ isReader,
+ mode,
+ parentName,
+ offsetText,
+ "::android::hardware::hidl_handle",
+ "" /* childName */,
+ "::android::hardware");
+}
+
+void HandleType::emitJavaFieldInitializer(
+ Formatter &out, const std::string &fieldName) const {
+ const std::string fieldDeclaration = getJavaType(false) + " " + fieldName;
+ emitJavaFieldDefaultInitialValue(out, fieldDeclaration);
+}
+
+void HandleType::emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const {
+ out << declaredFieldName
+ << " = new "
+ << getJavaType(true)
+ << "();\n";
+}
+
+void HandleType::emitJavaFieldReaderWriter(
+ Formatter &out,
+ size_t /* depth */,
+ const std::string &parcelName,
+ const std::string &blobName,
+ const std::string &fieldName,
+ const std::string &offset,
+ bool isReader) const {
if (isReader) {
- const std::string ptrName = "_hidl_" + sanitizedName + "_ptr";
+ out << fieldName
+ << " = "
+ << parcelName
+ << ".readEmbeddedNativeHandle(\n";
- out << "const native_handle_t *"
- << ptrName << ";\n"
- << "_hidl_err = "
- << parcelObj
- << (parcelObjIsPointer ? "->" : ".")
- << "readNullableEmbeddedNativeHandle(\n";
+ out.indent(2, [&] {
+ out << blobName
+ << ".handle(),\n"
+ << offset
+ << " + 0 /* offsetof(hidl_handle, mHandle) */);\n\n";
+ });
- out.indent();
- out.indent();
-
- out << parentName
- << ",\n"
- << offsetText
- << ",\n"
- << "&" << ptrName
- << "\n"
- << ");\n\n";
-
- out.unindent();
- out.unindent();
-
- handleError(out, mode);
- } else {
- out << "_hidl_err = "
- << parcelObj
- << (parcelObjIsPointer ? "->" : ".")
- << "writeEmbeddedNativeHandle(\n";
-
- out.indent();
- out.indent();
-
- out << (nameIsPointer ? ("*" + name) : name)
- << ",\n"
- << parentName
- << ",\n"
- << offsetText
- << ");\n\n";
-
- out.unindent();
- out.unindent();
-
- handleError(out, mode);
+ return;
}
+
+ out << blobName
+ << ".putNativeHandle("
+ << offset
+ << ", "
+ << fieldName
+ << ");\n";
}
bool HandleType::needsEmbeddedReadWrite() const {
@@ -158,7 +175,7 @@
}
bool HandleType::deepIsJavaCompatible(std::unordered_set<const Type*>* /* visited */) const {
- return false;
+ return true;
}
static HidlTypeAssertion assertion("hidl_handle", 16 /* size */);
diff --git a/HandleType.h b/HandleType.h
index feaddb0..8d3a984 100644
--- a/HandleType.h
+++ b/HandleType.h
@@ -33,6 +33,10 @@
StorageMode mode,
bool specifyNamespaces) const override;
+ std::string getJavaType(bool forInitializer) const override;
+
+ std::string getJavaSuffix() const override;
+
std::string getVtsType() const override;
void emitReaderWriter(
@@ -56,12 +60,25 @@
const std::string &parentName,
const std::string &offsetText) const override;
+ void emitJavaFieldInitializer(
+ Formatter &out, const std::string &fieldName) const override;
+
+ void emitJavaFieldDefaultInitialValue(
+ Formatter &out, const std::string &declaredFieldName) const override;
+
+ void emitJavaFieldReaderWriter(
+ Formatter &out,
+ size_t depth,
+ const std::string &parcelName,
+ const std::string &blobName,
+ const std::string &fieldName,
+ const std::string &offset,
+ bool isReader) const override;
+
bool needsEmbeddedReadWrite() const override;
bool deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const override;
- bool useNameInEmitReaderWriterEmbedded(bool isReader) const override;
-
void getAlignmentAndSize(size_t *align, size_t *size) const override;
void emitVtsTypeDeclarations(Formatter& out) const override;
diff --git a/Type.cpp b/Type.cpp
index c0e8fa8..6dba5c9 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -472,10 +472,6 @@
return needsResolveReferences();
}
-bool Type::useNameInEmitReaderWriterEmbedded(bool) const {
- return needsEmbeddedReadWrite();
-}
-
void Type::emitReaderWriterEmbedded(
Formatter &,
size_t,
diff --git a/Type.h b/Type.h
index 2d79915..0cac877 100644
--- a/Type.h
+++ b/Type.h
@@ -239,8 +239,6 @@
virtual bool useParentInEmitResolveReferencesEmbedded() const;
- virtual bool useNameInEmitReaderWriterEmbedded(bool isReader) const;
-
virtual void emitJavaReaderWriter(
Formatter &out,
const std::string &parcelObj,
diff --git a/test/hidl_test/hidl_test_client.cpp b/test/hidl_test/hidl_test_client.cpp
index a58ef8e..525f5f9 100644
--- a/test/hidl_test/hidl_test_client.cpp
+++ b/test/hidl_test/hidl_test_client.cpp
@@ -3,6 +3,7 @@
#include "FooCallback.h"
#include "hidl_test.h"
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android/hidl/manager/1.0/IServiceNotification.h>
@@ -58,6 +59,7 @@
#include <random>
#include <set>
#include <sstream>
+#include <sys/stat.h>
#include <thread>
#include <type_traits>
#include <unordered_set>
@@ -107,6 +109,7 @@
using ::android::wp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
@@ -144,6 +147,7 @@
using ::android::hidl::token::V1_0::ITokenManager;
using std::to_string;
+using HandleTypeSafeUnion = ISafeUnion::HandleTypeSafeUnion;
using InterfaceTypeSafeUnion = ISafeUnion::InterfaceTypeSafeUnion;
using LargeSafeUnion = ISafeUnion::LargeSafeUnion;
using SmallSafeUnion = ISafeUnion::SmallSafeUnion;
@@ -2063,6 +2067,196 @@
}));
}
+// 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_ARRAYEQ(&(reference->data[offset]), &(result->data[offset]), numInts);
+}
+
+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) {
diff --git a/test/java_test/hidl_test_java_native.cpp b/test/java_test/hidl_test_java_native.cpp
index bccefd4..04b6a87 100644
--- a/test/java_test/hidl_test_java_native.cpp
+++ b/test/java_test/hidl_test_java_native.cpp
@@ -17,6 +17,7 @@
//#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>
@@ -29,6 +30,10 @@
#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;
@@ -38,11 +43,13 @@
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::defaultPassthroughServiceImplementation;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using HandleTypeSafeUnion = ISafeUnion::HandleTypeSafeUnion;
using InterfaceTypeSafeUnion = ISafeUnion::InterfaceTypeSafeUnion;
using LargeSafeUnion = ISafeUnion::LargeSafeUnion;
using SmallSafeUnion = ISafeUnion::SmallSafeUnion;
@@ -122,6 +129,14 @@
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);
@@ -673,12 +688,52 @@
}));
}
+// 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::hidl_no_init,
@@ -707,6 +762,25 @@
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());
+ }
+ }));
}));
// Same-process interface calls are not supported in Java, so we use
@@ -720,6 +794,180 @@
hidl_string(testStringA), hidl_string(testStringB), [&](const hidl_string& result) {
EXPECT_EQ(testStringA + testStringB, std::string(result));
}));
+
+ 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) {
diff --git a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
index 8999bc3..222d9e2 100644
--- a/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
+++ b/test/java_test/src/com/android/commands/hidl_test_java/HidlTestJava.java
@@ -20,18 +20,26 @@
import android.hardware.tests.baz.V1_0.IBase;
import android.hardware.tests.baz.V1_0.IBaz;
import android.hardware.tests.baz.V1_0.IQuux;
+import android.hardware.tests.baz.V1_0.IBaz.MyHandle;
import android.hardware.tests.baz.V1_0.IBaz.NestedStruct;
import android.hardware.tests.baz.V1_0.IBazCallback;
import android.hardware.tests.safeunion.V1_0.IOtherInterface;
import android.hardware.tests.safeunion.V1_0.ISafeUnion;
+import android.hardware.tests.safeunion.V1_0.ISafeUnion.HandleTypeSafeUnion;
import android.hardware.tests.safeunion.V1_0.ISafeUnion.InterfaceTypeSafeUnion;
import android.hardware.tests.safeunion.V1_0.ISafeUnion.LargeSafeUnion;
import android.hardware.tests.safeunion.V1_0.ISafeUnion.SmallSafeUnion;
import android.os.HwBinder;
+import android.os.NativeHandle;
import android.os.RemoteException;
import android.os.HidlSupport;
import android.util.Log;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.NoSuchElementException;
@@ -51,7 +59,7 @@
System.exit(exitCode);
}
- public int run(String[] args) throws RemoteException {
+ public int run(String[] args) throws RemoteException, IOException {
if (args[0].equals("-c")) {
client();
} else if (args[0].equals("-s")) {
@@ -219,7 +227,7 @@
ExpectTrue(!HidlSupport.deepEquals(l, r));
}
- private void runClientSafeUnionTests() throws RemoteException {
+ private void runClientSafeUnionTests() throws RemoteException, IOException {
ISafeUnion safeunionInterface = ISafeUnion.getService();
{
@@ -276,6 +284,14 @@
ExpectTrue(safeUnion.l().a() == (byte) 1);
}
{
+ // SafeUnionInterfaceNullNativeHandleTest
+ InterfaceTypeSafeUnion safeUnion = new InterfaceTypeSafeUnion();
+
+ safeUnion = safeunionInterface.setInterfaceF(safeUnion, null);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.f);
+ ExpectTrue(safeUnion.f() == null);
+ }
+ {
// SafeUnionInterfaceTest
byte[] testArray = new byte[] {-1, -2, -3, 0, 1, 2, 3};
ArrayList<String> testVector = new ArrayList(Arrays.asList("So", "Many", "Words"));
@@ -284,6 +300,11 @@
IOtherInterface otherInterface = IOtherInterface.getService();
+ ArrayList<NativeHandle> testHandlesVector = new ArrayList<>();
+ for (int i = 0; i < 128; i++) {
+ testHandlesVector.add(new NativeHandle());
+ }
+
InterfaceTypeSafeUnion safeUnion = safeunionInterface.newInterfaceTypeSafeUnion();
safeUnion = safeunionInterface.setInterfaceB(safeUnion, testArray);
ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.b);
@@ -302,6 +323,108 @@
safeUnion = safeunionInterface.setInterfaceE(safeUnion, testVector);
ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.e);
ExpectDeepEq(testVector, safeUnion.e());
+
+ safeUnion = safeunionInterface.setInterfaceG(safeUnion, testHandlesVector);
+ ExpectTrue(safeUnion.getDiscriminator() == InterfaceTypeSafeUnion.hidl_discriminator.g);
+ ExpectTrue(safeUnion.g().size() == testHandlesVector.size());
+
+ for (int i = 0; i < testHandlesVector.size(); i++) {
+ ExpectFalse(safeUnion.g().get(i).hasSingleFileDescriptor());
+ }
+ }
+ {
+ // SafeUnionNullNativeHandleTest
+ HandleTypeSafeUnion safeUnion = new HandleTypeSafeUnion();
+
+ safeUnion = safeunionInterface.setHandleA(safeUnion, null);
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.a);
+ ExpectTrue(safeUnion.a() == null);
+ }
+ {
+ // SafeUnionDefaultNativeHandleTest
+ NativeHandle[] testHandlesArray = new NativeHandle[5];
+ for (int i = 0; i < testHandlesArray.length; i++) {
+ testHandlesArray[i] = new NativeHandle();
+ }
+
+ ArrayList<NativeHandle> testHandlesList = new ArrayList<NativeHandle>(
+ Arrays.asList(testHandlesArray));
+
+ HandleTypeSafeUnion safeUnion = safeunionInterface.newHandleTypeSafeUnion();
+ safeUnion = safeunionInterface.setHandleA(safeUnion, new NativeHandle());
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.a);
+ ExpectFalse(safeUnion.a().hasSingleFileDescriptor());
+
+ safeUnion = safeunionInterface.setHandleB(safeUnion, testHandlesArray);
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.b);
+ ExpectTrue(safeUnion.b().length == testHandlesArray.length);
+
+ for (int i = 0; i < testHandlesArray.length; i++) {
+ ExpectFalse(safeUnion.b()[i].hasSingleFileDescriptor());
+ }
+
+ safeUnion = safeunionInterface.setHandleC(safeUnion, testHandlesList);
+ ExpectTrue(safeUnion.getDiscriminator() == HandleTypeSafeUnion.hidl_discriminator.c);
+ ExpectTrue(safeUnion.c().size() == testHandlesList.size());
+
+ for (int i = 0; i < testHandlesList.size(); i++) {
+ ExpectFalse(safeUnion.c().get(i).hasSingleFileDescriptor());
+ }
+ }
+ {
+ // SafeUnionNativeHandleWithFdTest
+ final String testFileName = "/data/local/tmp/SafeUnionNativeHandleWithFdTest";
+ final String[] testStrings = {"This ", "is ", "so ", "much ", "data!\n"};
+ File file = new File(testFileName);
+
+ if (file.exists()) { ExpectTrue(file.delete()); }
+ ExpectTrue(file.createNewFile());
+
+ StringBuilder builder = new StringBuilder();
+ for (String testString : testStrings) {
+ builder.append(testString);
+ }
+ final String goldenResult = builder.toString();
+
+ ArrayList<NativeHandle> testHandlesList = new ArrayList<NativeHandle>();
+ FileOutputStream fos = new FileOutputStream(file);
+ for (int i = 0; i < testStrings.length; i++) {
+ testHandlesList.add(new NativeHandle(fos.getFD(), false /*own*/));
+ }
+
+ HandleTypeSafeUnion safeUnion = safeunionInterface.newHandleTypeSafeUnion();
+ safeUnion = safeunionInterface.setHandleC(safeUnion, testHandlesList);
+ for (int i = 0; i < safeUnion.c().size(); i++) {
+ ExpectTrue(safeUnion.c().get(i).hasSingleFileDescriptor());
+
+ // If you want to copy it out of the binder buffer or save it, it needs to be duped.
+ // This isn't necessary for the test since it is kept open for the binder window.
+ NativeHandle handle = safeUnion.c().get(i);
+ if (i%2 == 0) handle = handle.dup();
+
+ // Original fd is duped if not dup'd above
+ FileDescriptor resultFd = handle.getFileDescriptor();
+ ExpectTrue(resultFd.getInt$() != fos.getFD().getInt$());
+
+ FileOutputStream otherFos = new FileOutputStream(resultFd);
+ otherFos.write(testStrings[i].getBytes());
+ otherFos.flush();
+
+ otherFos.close();
+
+ if (i%2 == 0) handle.close();
+ }
+
+ byte[] resultData = new byte[(int) file.length()];
+ FileInputStream fis = new FileInputStream(file);
+ fis.read(resultData);
+
+ String result = new String(resultData);
+ Expect(result, goldenResult);
+
+ fis.close();
+ fos.close();
+ ExpectTrue(file.delete());
}
{
// SafeUnionEqualityTest
@@ -353,7 +476,7 @@
}
}
- private void client() throws RemoteException {
+ private void client() throws RemoteException, IOException {
ExpectDeepEq(null, null);
ExpectDeepNe(null, new String());
@@ -891,7 +1014,6 @@
ArrayList<double[]> out = proxy.testDoubleVecs(in);
ExpectTrue(in.equals(out));
}
-
{
// testProxyEquals
// TODO(b/68727931): test passthrough services as well.
@@ -1384,6 +1506,55 @@
return safeUnion;
}
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceF(
+ InterfaceTypeSafeUnion safeUnion, NativeHandle f) {
+ Log.d(TAG, "SERVER: setInterfaceF(" + f + ")");
+ safeUnion.f(f);
+
+ return safeUnion;
+ }
+
+ @Override
+ public InterfaceTypeSafeUnion setInterfaceG(
+ InterfaceTypeSafeUnion safeUnion, ArrayList<NativeHandle> g) {
+ Log.d(TAG, "SERVER: setInterfaceG(" + g + ")");
+ safeUnion.g(g);
+
+ return safeUnion;
+ }
+
+ @Override
+ public HandleTypeSafeUnion newHandleTypeSafeUnion() {
+ Log.d(TAG, "SERVER: newHandleTypeSafeUnion");
+ return new HandleTypeSafeUnion();
+ }
+
+ @Override
+ public HandleTypeSafeUnion setHandleA(HandleTypeSafeUnion safeUnion, NativeHandle a) {
+ Log.d(TAG, "SERVER: setHandleA(" + a + ")");
+ safeUnion.a(a);
+
+ return safeUnion;
+ }
+
+ @Override
+ public HandleTypeSafeUnion setHandleB(HandleTypeSafeUnion safeUnion, NativeHandle[] b) {
+ Log.d(TAG, "SERVER: setHandleB(" + b + ")");
+ safeUnion.b(b);
+
+ return safeUnion;
+ }
+
+ @Override
+ public HandleTypeSafeUnion setHandleC(HandleTypeSafeUnion safeUnion,
+ ArrayList<NativeHandle> c) {
+ Log.d(TAG, "SERVER: setHandleC(" + c + ")");
+ safeUnion.c(c);
+
+ return safeUnion;
+ }
}
class OtherInterface extends IOtherInterface.Stub {