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

Commit 6dd325b9 authored by Dan Stoza's avatar Dan Stoza
Browse files

libbinder: Support sp<Flattenable> in SafeInterface

Adds support for sending and receiving sp<Flattenable> parameters (such
as sp<Fence> and sp<GraphicBuffer>) as part of a SafeInterface.

Test: New test in binderSafeInterfaceTest
Change-Id: I36ba19c7f121771e9a7acfde9ed164e1cd3200b3
parent 662a899e
Loading
Loading
Loading
Loading
+19 −1
Original line number Diff line number Diff line
@@ -55,6 +55,17 @@ public:
        return callParcel("write(Flattenable)", [&]() { return parcel->write(t); });
    }
    template <typename T>
    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type read(
            const Parcel& parcel, sp<T>* t) const {
        *t = new T{};
        return callParcel("read(sp<Flattenable>)", [&]() { return parcel.read(*(t->get())); });
    }
    template <typename T>
    typename std::enable_if<std::is_base_of<Flattenable<T>, T>::value, status_t>::type write(
            Parcel* parcel, const sp<T>& t) const {
        return callParcel("write(sp<Flattenable>)", [&]() { return parcel->write(*(t.get())); });
    }
    template <typename T>
    typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
            const Parcel& parcel, T* t) const {
        return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
@@ -81,7 +92,8 @@ public:
        return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
    }
    template <typename T>
    status_t read(const Parcel& parcel, sp<T>* pointer) const {
    typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type read(
            const Parcel& parcel, sp<T>* pointer) const {
        return callParcel("readNullableStrongBinder",
                          [&]() { return parcel.readNullableStrongBinder(pointer); });
    }
@@ -92,6 +104,12 @@ public:
                          [&]() { return parcel->writeStrongBinder(pointer); });
    }
    template <typename T>
    typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type read(
            const Parcel& parcel, sp<T>* pointer) const {
        return callParcel("readNullableStrongBinder[IInterface]",
                          [&]() { return parcel.readNullableStrongBinder(pointer); });
    }
    template <typename T>
    typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
            Parcel* parcel, const sp<T>& interface) const {
        return write(parcel, IInterface::asBinder(interface));
+56 −0
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@
#include <gtest/gtest.h>
#pragma clang diagnostic pop

#include <utils/LightRefBase.h>

#include <optional>

using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
@@ -90,6 +92,30 @@ struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
    int32_t value = 0;
};

// It seems like this should be able to inherit from TestFlattenable (to avoid duplicating code),
// but the SafeInterface logic can't easily be extended to find an indirect Flattenable<T>
// base class
class TestLightRefBaseFlattenable : public Flattenable<TestLightRefBaseFlattenable>,
                                    public LightRefBase<TestLightRefBaseFlattenable> {
public:
    TestLightRefBaseFlattenable() = default;
    explicit TestLightRefBaseFlattenable(int32_t v) : value(v) {}

    // Flattenable protocol
    size_t getFlattenedSize() const { return sizeof(value); }
    size_t getFdCount() const { return 0; }
    status_t flatten(void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const {
        FlattenableUtils::write(buffer, size, value);
        return NO_ERROR;
    }
    status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
        FlattenableUtils::read(buffer, size, value);
        return NO_ERROR;
    }

    int32_t value = 0;
};

class ExitOnDeath : public IBinder::DeathRecipient {
public:
    ~ExitOnDeath() override = default;
@@ -163,6 +189,7 @@ public:
        LogicalNot,
        IncrementFlattenable,
        IncrementLightFlattenable,
        IncrementLightRefBaseFlattenable,
        IncrementNoCopyNoMove,
        ToUpper,
        CallMeBack,
@@ -186,6 +213,8 @@ public:
    virtual status_t increment(const TestFlattenable& a, TestFlattenable* aPlusOne) const = 0;
    virtual status_t increment(const TestLightFlattenable& a,
                               TestLightFlattenable* aPlusOne) const = 0;
    virtual status_t increment(const sp<TestLightRefBaseFlattenable>& a,
                               sp<TestLightRefBaseFlattenable>* 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
@@ -230,6 +259,12 @@ public:
        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
        return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
    }
    status_t increment(const sp<TestLightRefBaseFlattenable>& a,
                       sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
        using Signature = status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
                                                           sp<TestLightRefBaseFlattenable>*) const;
        return callRemote<Signature>(Tag::IncrementLightRefBaseFlattenable, 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,
@@ -315,6 +350,12 @@ public:
        aPlusOne->value = a.value + 1;
        return NO_ERROR;
    }
    status_t increment(const sp<TestLightRefBaseFlattenable>& a,
                       sp<TestLightRefBaseFlattenable>* aPlusOne) const override {
        ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
        *aPlusOne = new TestLightRefBaseFlattenable(a->value + 1);
        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);
@@ -384,6 +425,12 @@ public:
                                                         TestLightFlattenable* aPlusOne) const;
                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
            }
            case ISafeInterfaceTest::Tag::IncrementLightRefBaseFlattenable: {
                using Signature =
                        status_t (ISafeInterfaceTest::*)(const sp<TestLightRefBaseFlattenable>&,
                                                         sp<TestLightRefBaseFlattenable>*) const;
                return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
            }
            case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
                using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
                                                                   NoCopyNoMove* aPlusOne) const;
@@ -513,6 +560,15 @@ TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
    ASSERT_EQ(a.value + 1, aPlusOne.value);
}

TEST_F(SafeInterfaceTest, TestIncrementLightRefBaseFlattenable) {
    sp<TestLightRefBaseFlattenable> a = new TestLightRefBaseFlattenable{1};
    sp<TestLightRefBaseFlattenable> aPlusOne;
    status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
    ASSERT_EQ(NO_ERROR, result);
    ASSERT_NE(nullptr, aPlusOne.get());
    ASSERT_EQ(a->value + 1, aPlusOne->value);
}

TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
    const NoCopyNoMove a{1};
    NoCopyNoMove aPlusOne{0};