diff options
| -rw-r--r-- | libs/binder/include/binder/SafeInterface.h | 14 | ||||
| -rw-r--r-- | libs/binder/tests/Android.bp | 1 | ||||
| -rw-r--r-- | libs/binder/tests/binderSafeInterfaceTest.cpp | 75 |
3 files changed, 90 insertions, 0 deletions
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h index f931304b95..15a75b0285 100644 --- a/libs/binder/include/binder/SafeInterface.h +++ b/libs/binder/include/binder/SafeInterface.h @@ -26,6 +26,8 @@ #include <utils/CallStack.h> #endif +#include <utils/NativeHandle.h> + #include <functional> #include <type_traits> @@ -88,6 +90,18 @@ public: Parcel* parcel, const T& t) const { return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); }); } + template <typename NH> + typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type read( + const Parcel& parcel, NH* nh) { + *nh = NativeHandle::create(parcel.readNativeHandle(), true); + return NO_ERROR; + } + template <typename NH> + typename std::enable_if<std::is_same<NH, sp<NativeHandle>>::value, status_t>::type write( + Parcel* parcel, const NH& nh) { + return callParcel("write(sp<NativeHandle>)", + [&]() { return parcel->writeNativeHandle(nh->handle()); }); + } template <typename T> typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read( const Parcel& parcel, T* t) const { diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 1ee4b6f741..853ca1630e 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -100,6 +100,7 @@ cc_test { shared_libs: [ "libbinder", + "libcutils", "liblog", "libutils", ], diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index ccb023d2ce..4d9cacb80d 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -29,9 +29,14 @@ #pragma clang diagnostic pop #include <utils/LightRefBase.h> +#include <utils/NativeHandle.h> + +#include <cutils/native_handle.h> #include <optional> +#include <sys/eventfd.h> + using namespace std::chrono_literals; // NOLINT - google-build-using-namespace namespace android { @@ -197,6 +202,7 @@ public: IncrementFlattenable, IncrementLightFlattenable, IncrementLightRefBaseFlattenable, + IncrementNativeHandle, IncrementNoCopyNoMove, ToUpper, CallMeBack, @@ -223,6 +229,7 @@ public: TestLightFlattenable* aPlusOne) const = 0; virtual status_t increment(const sp<TestLightRefBaseFlattenable>& a, sp<TestLightRefBaseFlattenable>* aPlusOne) const = 0; + virtual status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const = 0; virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0; virtual status_t toUpper(const String8& str, String8* upperStr) const = 0; // As mentioned above, sp<IBinder> is already tested by setDeathToken @@ -277,6 +284,12 @@ public: sp<TestLightRefBaseFlattenable>*) const; return callRemote<Signature>(Tag::IncrementLightRefBaseFlattenable, a, aPlusOne); } + status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + using Signature = + status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&, sp<NativeHandle>*) const; + return callRemote<Signature>(Tag::IncrementNativeHandle, a, aPlusOne); + } status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a, @@ -373,6 +386,22 @@ public: *aPlusOne = new TestLightRefBaseFlattenable(a->value + 1); return NO_ERROR; } + status_t increment(const sp<NativeHandle>& a, sp<NativeHandle>* aPlusOne) const override { + ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); + native_handle* rawHandle = native_handle_create(1 /*numFds*/, 1 /*numInts*/); + if (rawHandle == nullptr) return NO_MEMORY; + + // Copy the fd over directly + rawHandle->data[0] = dup(a->handle()->data[0]); + + // Increment the int + rawHandle->data[1] = a->handle()->data[1] + 1; + + // This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing + // the native_handle when it goes out of scope + *aPlusOne = NativeHandle::create(rawHandle, true); + return NO_ERROR; + } status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override { ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__); aPlusOne->setValue(a.getValue() + 1); @@ -451,6 +480,11 @@ public: sp<TestLightRefBaseFlattenable>*) const; return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); } + case ISafeInterfaceTest::Tag::IncrementNativeHandle: { + using Signature = status_t (ISafeInterfaceTest::*)(const sp<NativeHandle>&, + sp<NativeHandle>*) const; + return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment); + } case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: { using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const; @@ -597,6 +631,47 @@ TEST_F(SafeInterfaceTest, TestIncrementLightRefBaseFlattenable) { ASSERT_EQ(a->value + 1, aPlusOne->value); } +namespace { // Anonymous namespace + +bool fdsAreEquivalent(int a, int b) { + struct stat statA {}; + struct stat statB {}; + if (fstat(a, &statA) != 0) return false; + if (fstat(b, &statB) != 0) return false; + return (statA.st_dev == statB.st_dev) && (statA.st_ino == statB.st_ino); +} + +} // Anonymous namespace + +TEST_F(SafeInterfaceTest, TestIncrementNativeHandle) { + // Create an fd we can use to send and receive from the remote process + base::unique_fd eventFd{eventfd(0 /*initval*/, 0 /*flags*/)}; + ASSERT_NE(-1, eventFd); + + // Determine the maximum number of fds this process can have open + struct rlimit limit {}; + ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &limit)); + uint32_t maxFds = static_cast<uint32_t>(limit.rlim_cur); + + // Perform this test enough times to rule out fd leaks + for (uint32_t iter = 0; iter < (2 * maxFds); ++iter) { + native_handle* handle = native_handle_create(1 /*numFds*/, 1 /*numInts*/); + ASSERT_NE(nullptr, handle); + handle->data[0] = dup(eventFd.get()); + handle->data[1] = 1; + + // This cannot fail, as it is just the sp<NativeHandle> taking responsibility for closing + // the native_handle when it goes out of scope + sp<NativeHandle> a = NativeHandle::create(handle, true); + + sp<NativeHandle> aPlusOne; + status_t result = mSafeInterfaceTest->increment(a, &aPlusOne); + ASSERT_EQ(NO_ERROR, result); + ASSERT_TRUE(fdsAreEquivalent(a->handle()->data[0], aPlusOne->handle()->data[0])); + ASSERT_EQ(a->handle()->data[1] + 1, aPlusOne->handle()->data[1]); + } +} + TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) { const NoCopyNoMove a{1}; NoCopyNoMove aPlusOne{0}; |