Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2537db72 authored by Dan Stoza's avatar Dan Stoza
Browse files

libbinder: Add sp<NativeHandle> to SafeInterface

Adds support for sending and receiving sp<NativeHandle> parameters as
part of a SafeInterface.

Test: New test in binderSafeInterfaceTest
Change-Id: Ia402b4bceedff358864669d201b4c1e22be6d0fa
parent 81ea3efb
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -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 {
+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ cc_test {

    shared_libs: [
        "libbinder",
        "libcutils",
        "liblog",
        "libutils",
    ],
+75 −0
Original line number Diff line number Diff line
@@ -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};