diff options
author | Steven Moreland <smoreland@google.com> | 2020-12-15 00:13:40 +0000 |
---|---|---|
committer | Steven Moreland <smoreland@google.com> | 2020-12-15 16:45:20 +0000 |
commit | 74e043ba2d7b75fc68c6bee1d09c333480734fd9 (patch) | |
tree | 7fdb5fa1f13d381794bf1ba26417819cbb0cacc7 /common | |
parent | baf61434fd49d96b4f4f3a143059a2f332d3b3f2 (diff) | |
download | platform_hardware_interfaces-74e043ba2d7b75fc68c6bee1d09c333480734fd9.tar.gz platform_hardware_interfaces-74e043ba2d7b75fc68c6bee1d09c333480734fd9.tar.bz2 platform_hardware_interfaces-74e043ba2d7b75fc68c6bee1d09c333480734fd9.zip |
support lib for libcutils<->NDK AIDL handle
The native_handle API is notoriously tricky to work with, and this is
expected to be very common. So, adding a small helper library.
Fixes: 175432703
Test: atest libaidlcommonsupport_test
Change-Id: I4a00d2b14fefe6c979ee656e353e117661a1a483
Diffstat (limited to 'common')
-rw-r--r-- | common/TEST_MAPPING | 7 | ||||
-rw-r--r-- | common/support/Android.bp | 27 | ||||
-rw-r--r-- | common/support/NativeHandle.cpp | 66 | ||||
-rw-r--r-- | common/support/include/aidlcommonsupport/NativeHandle.h | 53 | ||||
-rw-r--r-- | common/support/test.cpp | 138 |
5 files changed, 291 insertions, 0 deletions
diff --git a/common/TEST_MAPPING b/common/TEST_MAPPING new file mode 100644 index 0000000000..7dd29e5247 --- /dev/null +++ b/common/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "libaidlcommonsupport_test" + } + ] +} diff --git a/common/support/Android.bp b/common/support/Android.bp new file mode 100644 index 0000000000..3bb48049f3 --- /dev/null +++ b/common/support/Android.bp @@ -0,0 +1,27 @@ +cc_library_static { + name: "libaidlcommonsupport", + vendor_available: true, + host_supported: true, + defaults: ["libbinder_ndk_host_user"], + srcs: ["NativeHandle.cpp"], + export_include_dirs: ["include"], + shared_libs: [ + "android.hardware.common-unstable-ndk_platform", + "libcutils", + ], +} + +cc_test { + name: "libaidlcommonsupport_test", + host_supported: true, + defaults: ["libbinder_ndk_host_user"], + srcs: ["test.cpp"], + static_libs: [ + "libaidlcommonsupport", + ], + shared_libs: [ + "android.hardware.common-unstable-ndk_platform", + "libcutils", + ], + test_suites: ["general-tests"], +} diff --git a/common/support/NativeHandle.cpp b/common/support/NativeHandle.cpp new file mode 100644 index 0000000000..321d7a8cba --- /dev/null +++ b/common/support/NativeHandle.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 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 <aidlcommonsupport/NativeHandle.h> + +#include <fcntl.h> + +namespace android { + +using aidl::android::hardware::common::NativeHandle; + +static native_handle_t* fromAidl(const NativeHandle& handle, bool doDup) { + native_handle_t* to = native_handle_create(handle.fds.size(), handle.ints.size()); + if (!to) return nullptr; + + for (size_t i = 0; i < handle.fds.size(); i++) { + int fd = handle.fds[i].get(); + to->data[i] = doDup ? fcntl(fd, F_DUPFD_CLOEXEC, 0) : fd; + } + memcpy(to->data + handle.fds.size(), handle.ints.data(), handle.ints.size() * sizeof(int)); + return to; +} + +native_handle_t* makeFromAidl(const NativeHandle& handle) { + return fromAidl(handle, false /* doDup */); +} +native_handle_t* dupFromAidl(const NativeHandle& handle) { + return fromAidl(handle, true /* doDup */); +} + +static NativeHandle toAidl(const native_handle_t* handle, bool doDup) { + NativeHandle to; + + to.fds = std::vector<ndk::ScopedFileDescriptor>(handle->numFds); + for (size_t i = 0; i < handle->numFds; i++) { + int fd = handle->data[i]; + to.fds.at(i).set(doDup ? fcntl(fd, F_DUPFD_CLOEXEC, 0) : fd); + } + + to.ints = std::vector<int32_t>(handle->data + handle->numFds, + handle->data + handle->numFds + handle->numInts); + return to; +} + +NativeHandle makeToAidl(const native_handle_t* handle) { + return toAidl(handle, false /* doDup */); +} + +NativeHandle dupToAidl(const native_handle_t* handle) { + return toAidl(handle, true /* doDup */); +} + +} // namespace android diff --git a/common/support/include/aidlcommonsupport/NativeHandle.h b/common/support/include/aidlcommonsupport/NativeHandle.h new file mode 100644 index 0000000000..10eecbaca3 --- /dev/null +++ b/common/support/include/aidlcommonsupport/NativeHandle.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 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 <aidl/android/hardware/common/NativeHandle.h> +#include <cutils/native_handle.h> + +namespace android { + +/** + * Creates a libcutils native handle from an AIDL native handle, but it does not + * dup internally, so it will contain the same FDs as the handle itself. The + * result should be deleted with native_handle_delete. + */ +native_handle_t* makeFromAidl(const aidl::android::hardware::common::NativeHandle& handle); + +/** + * Creates a libcutils native handle from an AIDL native handle with a dup + * internally. It's expected the handle is cleaned up with native_handle_close + * and native_handle_delete. + */ +native_handle_t* dupFromAidl(const aidl::android::hardware::common::NativeHandle& handle); + +/** + * Creates an AIDL native handle from a libcutils native handle, but does not + * dup internally, so the result will contain the same FDs as the handle itself. + * + * Warning: this passes ownership of the FDs to the ScopedFileDescriptor + * objects. + */ +aidl::android::hardware::common::NativeHandle makeToAidl(const native_handle_t* handle); + +/** + * Creates an AIDL native handle from a libcutils native handle with a dup + * internally. + */ +aidl::android::hardware::common::NativeHandle dupToAidl(const native_handle_t* handle); + +} // namespace android diff --git a/common/support/test.cpp b/common/support/test.cpp new file mode 100644 index 0000000000..235927709c --- /dev/null +++ b/common/support/test.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2020 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 <aidlcommonsupport/NativeHandle.h> +#include <gtest/gtest.h> + +namespace android { + +using aidl::android::hardware::common::NativeHandle; +using ndk::ScopedFileDescriptor; + +static void checkEq(const NativeHandle& aidl, native_handle_t* libcutils, bool exceptFds) { + ASSERT_NE(libcutils, nullptr); + ASSERT_EQ(libcutils->numFds, aidl.fds.size()); + + for (size_t i = 0; i < libcutils->numFds; i++) { + int afd = aidl.fds.at(i).get(); + int lfd = libcutils->data[i]; + + EXPECT_GE(afd, 0) << "Invalid fd at index " << i; + EXPECT_GE(lfd, 0) << "Invalid fd at index " << i; + + if (exceptFds) { + EXPECT_NE(afd, lfd) << "Index matched at " << i << " but should be dup'd fd"; + } else { + EXPECT_EQ(afd, lfd) << "Index mismatched at " << i << " but should be same fd"; + } + } + + ASSERT_EQ(libcutils->numInts, aidl.ints.size()); + + for (size_t i = 0; i < libcutils->numInts; i++) { + int afd = aidl.ints.at(i); + int lfd = libcutils->data[libcutils->numFds + i]; + + EXPECT_EQ(afd, lfd) << "Index mismatch at " << i; + } +} + +static NativeHandle makeTestAidlHandle() { + NativeHandle handle = { + .fds = std::vector<ScopedFileDescriptor>(2), + .ints = {1, 2, 3, 4}, + }; + handle.fds[0].set(dup(0)); + handle.fds[1].set(dup(0)); + return handle; +} + +TEST(ConvertNativeHandle, MakeFromAidlEmpty) { + NativeHandle handle; + native_handle_t* to = makeFromAidl(handle); + checkEq(handle, to, false /*exceptFds*/); + // no native_handle_close b/c fds are owned by NativeHandle + EXPECT_EQ(0, native_handle_delete(to)); +} + +TEST(ConvertNativeHandle, MakeFromAidl) { + NativeHandle handle = makeTestAidlHandle(); + native_handle_t* to = makeFromAidl(handle); + checkEq(handle, to, false /*exceptFds*/); + // no native_handle_close b/c fds are owned by NativeHandle + EXPECT_EQ(0, native_handle_delete(to)); +} + +TEST(ConvertNativeHandle, DupFromAidlEmpty) { + NativeHandle handle; + native_handle_t* to = dupFromAidl(handle); + checkEq(handle, to, true /*exceptFds*/); + EXPECT_EQ(0, native_handle_close(to)); + EXPECT_EQ(0, native_handle_delete(to)); +} + +TEST(ConvertNativeHandle, DupFromAidl) { + NativeHandle handle = makeTestAidlHandle(); + native_handle_t* to = dupFromAidl(handle); + checkEq(handle, to, true /*exceptFds*/); + EXPECT_EQ(0, native_handle_close(to)); + EXPECT_EQ(0, native_handle_delete(to)); +} + +static native_handle_t* makeTestLibcutilsHandle() { + native_handle_t* handle = native_handle_create(2, 4); + handle->data[0] = dup(0); + handle->data[1] = dup(0); + handle->data[2] = 1; + handle->data[3] = 2; + handle->data[4] = 3; + handle->data[5] = 4; + return handle; +} + +TEST(ConvertNativeHandle, MakeToAidlEmpty) { + native_handle_t* handle = native_handle_create(0, 0); + NativeHandle to = makeToAidl(handle); + checkEq(to, handle, false /*exceptFds*/); + // no native_handle_close b/c fds are owned by NativeHandle now + EXPECT_EQ(0, native_handle_delete(handle)); +} + +TEST(ConvertNativeHandle, MakeToAidl) { + native_handle_t* handle = makeTestLibcutilsHandle(); + NativeHandle to = makeToAidl(handle); + checkEq(to, handle, false /*exceptFds*/); + // no native_handle_close b/c fds are owned by NativeHandle now + EXPECT_EQ(0, native_handle_delete(handle)); +} + +TEST(ConvertNativeHandle, DupToAidlEmpty) { + native_handle_t* handle = native_handle_create(0, 0); + NativeHandle to = dupToAidl(handle); + checkEq(to, handle, true /*exceptFds*/); + EXPECT_EQ(0, native_handle_close(handle)); + EXPECT_EQ(0, native_handle_delete(handle)); +} + +TEST(ConvertNativeHandle, DupToAidl) { + native_handle_t* handle = makeTestLibcutilsHandle(); + NativeHandle to = dupToAidl(handle); + checkEq(to, handle, true /*exceptFds*/); + EXPECT_EQ(0, native_handle_close(handle)); + EXPECT_EQ(0, native_handle_delete(handle)); +} + +} // namespace android |