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

Commit 8c9d2483 authored by Marin Shalamanov's avatar Marin Shalamanov
Browse files

Serialize LightFlattenable trivially copyable objects as LightFlattenable

Currently if an object is LightFlattenable and trivially copyable
FlattenableHelpers serialize it as a trivially copyable. Instead
the overloaded methods should be used.

Bug: 180539476
Test: atest FlattenableHelpersTest
Change-Id: I37d9c207db6bf7be869d919e3d96b85dc3a6cd16
parent 75f37254
Loading
Loading
Loading
Loading
+13 −4
Original line number Original line Diff line number Diff line
@@ -29,20 +29,29 @@
namespace android {
namespace android {


struct FlattenableHelpers {
struct FlattenableHelpers {
    // Helpers for reading and writing POD structures
    // Helpers for reading and writing POD structures which are not LightFlattenable.
    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
    template <class T,
              typename = std::enable_if_t<
                      std::conjunction_v<std::is_trivially_copyable<T>,
                                         std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
    static constexpr size_t getFlattenedSize(const T&) {
    static constexpr size_t getFlattenedSize(const T&) {
        return sizeof(T);
        return sizeof(T);
    }
    }


    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
    template <class T,
              typename = std::enable_if_t<
                      std::conjunction_v<std::is_trivially_copyable<T>,
                                         std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
    static status_t flatten(void** buffer, size_t* size, const T& value) {
    static status_t flatten(void** buffer, size_t* size, const T& value) {
        if (*size < sizeof(T)) return NO_MEMORY;
        if (*size < sizeof(T)) return NO_MEMORY;
        FlattenableUtils::write(*buffer, *size, value);
        FlattenableUtils::write(*buffer, *size, value);
        return OK;
        return OK;
    }
    }


    template <class T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
    template <class T,
              typename = std::enable_if_t<
                      std::conjunction_v<std::is_trivially_copyable<T>,
                                         std::negation<std::is_base_of<LightFlattenable<T>, T>>>>>
    static status_t unflatten(const void** buffer, size_t* size, T* value) {
    static status_t unflatten(const void** buffer, size_t* size, T* value) {
        if (*size < sizeof(T)) return NO_MEMORY;
        if (*size < sizeof(T)) return NO_MEMORY;
        FlattenableUtils::read(*buffer, *size, *value);
        FlattenableUtils::read(*buffer, *size, *value);
+62 −1
Original line number Original line Diff line number Diff line
@@ -42,7 +42,7 @@ struct TestLightFlattenable : LightFlattenable<TestLightFlattenable> {
    }
    }


    status_t unflatten(void const* buffer, size_t size) {
    status_t unflatten(void const* buffer, size_t size) {
        int value;
        int32_t value;
        FlattenableUtils::read(buffer, size, value);
        FlattenableUtils::read(buffer, size, value);
        ptr = std::make_unique<int32_t>(value);
        ptr = std::make_unique<int32_t>(value);
        return OK;
        return OK;
@@ -132,5 +132,66 @@ TEST_F(FlattenableHelpersTest, NullOptionalOfLightFlattenable) {
    ASSERT_FALSE(valueRead.has_value());
    ASSERT_FALSE(valueRead.has_value());
}
}


// If a struct is both trivially copyable and light flattenable we should treat it
// as LigthFlattenable.
TEST_F(FlattenableHelpersTest, TriviallyCopyableAndLightFlattenableIsFlattenedAsLightFlattenable) {
    static constexpr int32_t kSizeTag = 1234567;
    static constexpr int32_t kFlattenTag = 987654;
    static constexpr int32_t kUnflattenTag = 5926582;

    struct LightFlattenableAndTriviallyCopyable
          : LightFlattenable<LightFlattenableAndTriviallyCopyable> {
        int32_t value;

        bool isFixedSize() const { return true; }
        size_t getFlattenedSize() const { return kSizeTag; }

        status_t flatten(void* buffer, size_t size) const {
            FlattenableUtils::write(buffer, size, kFlattenTag);
            return OK;
        }

        status_t unflatten(void const*, size_t) {
            value = kUnflattenTag;
            return OK;
        }
    };

    {
        // Verify that getFlattenedSize uses the LightFlattenable overload
        LightFlattenableAndTriviallyCopyable foo;
        EXPECT_EQ(kSizeTag, FlattenableHelpers::getFlattenedSize(foo));
    }

    {
        // Verify that flatten uses the LightFlattenable overload
        std::vector<int8_t> buffer(sizeof(int32_t));
        auto rawBuffer = reinterpret_cast<void*>(buffer.data());
        size_t size = buffer.size();
        LightFlattenableAndTriviallyCopyable foo;
        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, foo));

        auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());
        int32_t value;
        FlattenableHelpers::unflatten(&rawReadBuffer, &size, &value);
        EXPECT_EQ(kFlattenTag, value);
    }

    {
        // Verify that unflatten uses the LightFlattenable overload
        std::vector<int8_t> buffer(sizeof(int32_t));
        auto rawBuffer = reinterpret_cast<void*>(buffer.data());
        size_t size = buffer.size();
        int32_t value = 4;
        ASSERT_EQ(OK, FlattenableHelpers::flatten(&rawBuffer, &size, value));

        auto rawReadBuffer = reinterpret_cast<const void*>(buffer.data());

        LightFlattenableAndTriviallyCopyable foo;
        FlattenableHelpers::unflatten(&rawReadBuffer, &size, &foo);
        EXPECT_EQ(kUnflattenTag, foo.value);
    }
}

} // namespace
} // namespace
} // namespace android
} // namespace android